0

Einfache XML-Serialisierung in C#

C# XML SerialisierungHeute möchte ich euch zeigen, wie man eine XML-Serialisierung in C# durchführen kann. Serialisierung selbst, bedeutet, dass man ein Objekt in eine andere, transportable Form umwandelt. Mittels XML-Serialisierung ist es uns zum Beispiel nötig, ein Objekt einer Klasse in Form einer XML-Datei abzuspeichern und auch wieder herzustellen.
Das kann Sinn machen, wenn man ein Objekt in seinem Zustand nach dem Schließen und erneuten Öffnen einer Anwendung wiederherstellen oder wenn man ein Objekt beispielsweise per HTTP übertragen möchte.

Für unser Beispiel habe ich folgende Klasse Blog erstellt:

public class Blog
{
    public string User { get; set; }
    public string Pass { get; set; }
    public string Subdomain { get; set; }
    public string BaseUrl { get; set; }
}

Die Methode zum Serialisieren sieht wie folgt aus:

public void SerializeBlogToXML(Blog blogObj)
{
    //Erstelle einen XML-Serialisierer für Objekte vom Typ Blog
    XmlSerializer serializer = new XmlSerializer(typeof(Blog));

    //Erstelle einen FileStream auf die Datei, in die unserer
    //Blog-Objekt in XML-Form gespeichert werden soll.
    FileStream file = new FileStream(Application.StartupPath
                                     + "\\blog.xml",
                                     FileMode.Create);
    //Serialisiere das übergebene Blog-Objekt (blogObj)
    //und schreibe es in den FileStream.
    serializer.Serialize(file, blogObj);

    //Schließe die XML-Datei.
    file.Close();
}

Nicht vergessen die passenden Using-Anweisungen zu schreiben!

using System.Xml.Serialization;
using System.IO;

Ohne diese würde die oben geschriebene Methode SerializeBlogToXML nicht ohne weitere Anpassungen laufen.

Das war es auch schon. Wenn man von meinen Kommentaren absieht, dann reichen ganze 4 Zeilen aus, um ein Objekt als XML-Datei abzuspeichern.

Ein kleines Beispiel zur Verwendung könnte zum Beispiel so aussehen:

private void buttonSerialisieren_Click(object sender, EventArgs e)
{
    //Blog-Objekt erstellen und mit Werten befüllen
    Blog blogObject = new Blog();
    blogObject.User = "maxmustermann";
    blogObject.Pass = "superpasswort";
    blogObject.Url = "www.code-bude.net";

    //Blog-Objekt serialisieren
    SerializeBlogToXML(blogObject);
}

Wenn alles geklappt hat, dürfte sich nun im Ausführungsverzeichnis eures Projektes eine Datei namens Blog.xml befinden. Diese sollte folgenden Inhalt haben:

<?xml version="1.0"?>
<Blog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <User>maxmustermann</User>
  <Pass>superpasswort</Pass>
  <Url>www.code-bude.net</Url>
</Blog>

Das einzige was jetzt noch fehlt, ist die Konvertierung eines nach XML serialisierten Objekts. Das geht sogar noch ein bisschen leichter, als das umwandeln in’s XML-Format.

public Blog DeserializeXmlToBlog()
{
    XmlSerializer serializer = new XmlSerializer(typeof(Blog));
    FileStream file = new FileStream(Application.StartupPath
                                        + "\\blog.xml",
                                        FileMode.Open);
    //Die Deserialize()-Methode gibt ein Object zurück. => casten!
    Blog blogList = serializer.Deserialize(file) as Blog;
    file.Close();
    return blogList;
}

Zum Abschluss noch mal ein Beispiel, in dem Serialisiert und Deserialisiert wird.

private void buttonSerialisieren_Click(object sender, EventArgs e)
{
    Blog blogObject = new Blog();
    blogObject.User = "maxmustermann";
    blogObject.Pass = "superpasswort";
    blogObject.Url = "www.code-bude.net";

    SerializeBlogToXML(blogObject);
    Blog blogFromXml = DeserializeXmlToBlog();
    MessageBox.Show(blogFromXml.Url);
}

Ich hoffe, ich habe das ganze verständlich genug beschrieben. Solltet ihr dennoch Fragen haben, schreibt mir einfach einen Kommentar.

Wer keine Lust hat, den Code von Hand zu tippen bzw. zu kopieren, der kann sich das Beispiel auch als Visual Studio 2010 Projekt herunterladen.

Viele Grüße,
Raffi

0

Höhe einer TextBox in C# verändern

Ich gebe zu, der Titel klingt geradezu trivial. Genauer betrachtet ist es aber gar nicht so einfach die Größe eines TextBox Controls in C# zu ändern, denn eine TextBox hat die Autosize-Eigenschaft nicht. Bei anderen Controls kann man die Autosize-Eigenschaft auf false setzen und dann die Höhe (Height-Property) verändern. Bei der TextBox geht dies so leider nicht.

Wie es doch geht, möchte ich euch nachfolgend zeigen. Der Trick ist folgender:

textBoxTest.Multiline = true;
textBoxTest.MinimumSize = new Size(150, 24);
textBoxTest.Size = new Size(150, 24);
textBoxTest.Multiline = false;

Zuerst muss man die Multiline-Eigenschaft auf true setzen. Danach kann man nach Lust und Laune die MinimumSize-, sowie die Size-Property anpassen, um die Größe der Textbox zu verändern. Wenn man fertig ist, setzt man die Multiline-Eigenschaft wieder auf false. Die TextBox behält die eben gesetzte Größe dennoch. So einfach ist das.

Wer sich jetzt noch fragt, wofür man das braucht, wenn die TextBox sich doch selbst in ihrer Größe anpasst, der sollte mal den BorderStyle auf “None” setzen und die Schriftgröße verändern. Möchte man nämlich eine TextBox ohne Rahmen anzeigen lassen und mit einer etwas größeren Schrift, so muss man feststellen, dass die automatische Größenanpassung nicht korrekt funktioniert. Das kann man auch gut an nachfolgendem Screenshot erkennen:

C# TextBox Height - TextBox Höhe verändernAuf dem Form befinden sich vier Textboxen:

1: Schriftgröße und BorderStyle unverändert
2: Schriftgröße erhöht, BorderStyle unverändert
3: Schriftgröße erhöht BorderStyle  = “None”
4: Schriftgröße erhöht, BorderStyle = “None”, Größe der Textbox angepasst

Wie man bei TextBox 3 sehen kann, funktioniert die Autosize-Funktion bei deaktiviertem Rahmen nicht mehr korrekt und gewisse Buchstaben werden nicht mehr vollständig dargestellt.

Hier schafft der eben von mir gezeigte Trick Abhilfe, wie man an TextBox 4 gut erkennen kann. Ich hoffe ich konnte hier mit mal wieder dem ein oder anderen helfen.

Viele Grüße,
Raffi

0

Benutzer im Active Directory suchen in C# – der einfache Weg

Vorgestern schrieb ich noch darüber, wie man die Active Directory Suchfunktion in Windows 7 erreicht. Heute soll es darum gehen, wie man in C# komfortabel das Active Directory nach Benutzern durchsuchen kann. Der Schwerpunkt liegt hierbei auf komfortabel, denn Artikel über die Thematik generell gibt es schon einige im Netz. Die meisten nutzen dafür jedoch ausschließlich die Methoden rund um System.DirectoryServices.ActiveDirectory und den DirectorySearcher. Doch seit .NET 3.5 geht es auch mit wesentlich weniger und vorallem, wie ich finde, verständlicherem Quelltext.

Doch kommen wir nun zur Sache. In dem folgenden Beispiel nutze ich hauptsächlich Methoden aus dem System.DirectoryServices.AccountManagement Namespace. Und so geht’s:

//Einen Kontext zur entsprechenden Windows Domäne erstellen
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain,
                                                      "meineDomaene");

//Ein "User-Objekt" im Kontext anlegen
UserPrincipal user = new UserPrincipal(domainContext);

//Den Suchparameter angeben
user.Name = "he*";

//Den Sucher anlegen und ihm die Suchkriterien
//(unser User-Objekt) übergeben
PrincipalSearcher pS = new PrincipalSearcher();
pS.QueryFilter = user;

//Die Suche durchführen
PrincipalSearchResult<Principal> results = pS.FindAll();

//Bei Bedarf weitere Details abfragen
Principal pc = results.ToList()[0];
DirectoryEntry de = (DirectoryEntry)pc.GetUnderlyingObject();

//Erstes Ergebnis zum Test ausgeben
MessageBox.Show(de.Properties["mail"].Value.ToString());

Nach dem ihr nun den Quelltext gesehen habt, gibt’s natürlich noch ein paar Hinweise dazu. In Zeile 9 habe ich die Name-Eigenschaft von user gesetzt. Das * gilt dabei als Wildcard. Es würden also in Zeile 17 alle Active Directory Benutzereinträge zurückgegeben, deren Name mit “he” anfängt und beliebig weiter geht.

Grundsätzlich lässt sich noch dazu sagen, dass ihr auch andere Eigenschaften, statt der Name-Eigenschaft, setzen könnt, die dann als Suchfilter fungieren. Auch das kombinieren von mehreren Eigenschaften ist möglich.

Außerdem möchte ich noch anmerken, das alles ab Zeile 21 optional ist. In den meisten Fällen dürften die Principal-Objekte reichen, die der PrincipalSearcher zurückgibt. Diese Principal-Objekte enthalten jedoch nicht alle Properties, die man so im Active Directory setzen kann.

Solltet ihr also eine Eigentschaft suchen, die das Principal Objekt nicht fasst, so müsst ihr auf den am Anfang des Artikels angesprochenen alten Weg zurückgreifen. Dazu wird das unterlegene Objekt des Principal mittels GetUnderlyingObject ermittelt und als DirectoryEntry gecastet. Diesem könnt ihr dann, wie in Zeile 24 gezeigt, alle beliebigen Informationen entnehmen.

Ich hoffe, ich konnte euch mit diesem Artikel ein wenig helfen. Viel Spaß damit. Solltet ihr noch Fragen haben, schreibt mir einfach einen Kommentar.

Viele Grüße,
Raffi

0

Kostenlose .NET-Decompiler – die .NET Reflector Alternativen

netreflectorHeute möchte ich euch kurz ein paar Alternativen zu Redgates .NET Reflector aufzeigen. Früher habe ich diesen zwar des Öfteren benutzt, doch seit dem dieser Geld kostet, und es gute und brauchbare kostenlose Alternativen, kommt dieser nicht mehr zwischen meine Finger.

Der nachfolgende Einschub ist für diejenigen gedacht, die mit dem Begriff .NET Reflector/Decompiler jetzt gerade gar nichts anfangen können. Die anderen lesen bitte einfach nach dem Einschub weiter.

Was ist ein (.NET-)Decompiler?

Decompiler nennt man Computerprogramme, die es ermöglichen aus Maschinencode/Objektbytecode wieder lesbaren Quelltext (in einer Hochsprache) zu zaubern. Sie stellen also das Gegenstück zu einem Compiler dar.

Praktisch kann man sich das wie folgt vorstellen. Der Programmierer schreibt den Quellcode für ein Programm. Diesen kompiliert er dann mit einem Compiler. Das Endergebnis nach dem kompilieren könnte dann zum Beispiel eine ausführbare .exe-Datei sein.

Nun kommen wir als ambitionierter Programmierer und Hobby-Raketentüftler daher und fragen uns, wie diese eine tolle Funktion wohl programmiert/geschrieben wurde. Wir wissen zufälligerweise, dass das Programm in C#.NET geschrieben wurde. Um nun nachzuschauen, wie der Programmierer diese tolle Funktion geschaffen hat, öffnen wir sein Programm (die .exe-Datei) in einem .NET-Decompiler und erhalten den lesbaren Quellcode seines Programms. Einer der bekannteren Decompiler für .Net-Code/-Anwendungen heißt .NET-Reflector.

Soviel vorerst zu der grundlegenden Funktionsweise eines .NET-Decompilers. Sicherlich klappt dies in der Praxis nicht in allen Fällen, da es natürlich auch Methoden gibt, seinen Quellcode mehr oder weniger vor dem Zugriff eines Decompilers zu schützen. Aber das würde an dieser Stelle den Rahmen sprengen. Wer mehr dazu erfahren will, sollte einfach mal nach “.NET Obfuscator” googeln.

Kommen wir nun zum eigentlichen Thema, den kostenlosen .NET- Decompilern. Spontan eingefallen bzw. gefunden habe ich folgenden vier Stück:

ILSpy (von SharpDevelop)

ilspy

JustDecompile (von Telerik)

justdecompile

DILE – Dotnet IL Editor (von zsozsop)

dotPeek (von JetBrains)

dotpeek

Funktioniert haben in meinen Test alle vier. Die Unterschiede liegen eher in der Einfachheit der Handhabung und der optischen Aufmachung. Mein persönlicher Favorit ist Just Decompile von Telerik. Jedoch muss man sich, um die Software zu nutzen, bei Telerik (kostenlos) registrieren.
Wer seine Daten nicht gerne abgibt, oder wem das einfach zu viel Aufwand ist, dem empfehle ich IL Spy. Das Programm ist kostenlos und Opensource. Der Download geht schnell, und ohne Registrierung, vonstatten und hinter dem Programm steht eine aktive Entwicklergemeinde.
Wie gesagt, die anderen beiden funktionierten bei mir auch, sagten mir aber nicht so sehr zu.

Zuletzt sei natürlich noch gesagt, dass alle vier Programme sehr “mächtig” sind. Bitte missbraucht diese “Macht” nicht, um Quellcode zu kopieren/zu klauen, sondern nutzt sie sinnvoll, um Fehler zu finden und/oder gewisse Funktionen zu verstehen.

Und nun würde mich noch interessieren, ob ihr auch .NET-Decompiler nutzt oder schon mal genutzt habt und wenn ja welchen und für was für einen Einsatzzweck?

Viele Grüße,
Raffi

0

Darstellungsfehler von Koreanischen und anderen ausländischen Zeichensätzen in C# / Visual Studio beheben

Ich weiß, der Titel des Posts ist grausam, aber ich wusste das Problem nicht kürzer zu beschreiben. Aber kommen wir nun zur Sache. Im Rahmen der Entwicklung meines Cloud Downloaders stieß ich unter anderem auf folgendes Problem. Koreanische Zeichen wurden nur als blanke Kästchen dargestellt, obwohl Sie im Quelltext korrekt angezeigt wurden. Wer sich jetzt fragt, wo man die koreanischen Zeichen auf einer deutschen Tastatur herbekommt, sollte einfach mal bei Google Translate vorbeischauen. (Der nachfolgende Screenshot veranschaulicht das Problem noch mal. Zum vergrößern bitte das Bild anklicken.)

Koreanische Zeichen falsche Darstellung

Im Netz habe ich nur sehr wenige Lösungen gefunden. Und fast alle waren meiner Meinung nach eher suboptimal. Meistens wird nämlich folgender Weg vorgeschlagen:

Es wird empfohlen die Methode SetCompatibleTextRenderingDefault() mit dem Parameter true aufzurufen. Hierdurch werden Texte mit der auf  GDI+ basierenden Graphics-Methode gerendert, welche zu Zeiten des .Net-Frameworks 1.x genutzt wurde.
Jedoch entstehen hierbei einige “Nachteile”. Zum einen werden die  Abstände bei der Graphics-Methode anders berechnet, sodass ein bestehendes Layout “auseinanderfallen” kann und zum anderen werden nicht alle Controls korrekt gerendert. (Ab .Net 2.0 wurde die auf GDI basierende TextRenderer Klasse eingeführt.)

Bezogen auf unsere Testapplikation sähe das wie folgt aus:

In der Program.cs aktivieren wir das DefaultTextRendering.

 static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(true);
            Application.Run(new Form1());
        }
    }
}

Und in der Applikation erhalten wir folgendes Ergebnis:
Koreanische Zeichen setcompatibletextrendering(true)
Wie man sieht, wird lediglich das Label korrekt dargestellt. Die Groupbox rendert die Zeichen weiterhin falsch.

Der andere Weg

Eine andere, und meiner Meinung nach eine bessere Lösung, ist der Weg über das Ändern der Schriftart/Font-Property. Es gibt ein paar Schriftarten, die wesentlich mehr Zeichensätze enthalten, als die ganzen Standardschriftarten. Eine davon ist zum Beispiel Arial Unicode MS, welche mit dem Microsoft Office mitgeliefert wird, aber auch auf MacOSX und auch einzeln verfügbar ist.
Setzt man nun diese Schriftart für alle seine Controls, erhält man folgendes Ergebnis:

namespace KoreanCharacters
{
    public partial class Form1 : Form
    {
        // [...]

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Font = new Font("Arial Unicode MS", 8.25f);
            foreach (Control con in GetAllControls(this))
                if (con.Font != null)
                    con.Font = new Font("Arial Unicode MS", 8.25f);

            this.Text = "안녕하세요";
            label1.Text = "안녕하세요";
            groupBox1.Text = "안녕하세요";
        }

        private static List<Control> GetAllControls(Control controlBase)
        {
            List<Control> controls = new List<Control>();
            foreach (Control con in controlBase.Controls)
            {
                controls.Add(con);
                List<Control> subControls = GetAllControls(con);
                controls.AddRange(subControls);
            }
            return controls;
        }
    }
}

Wie man sieht, wird nun auch der Text der Groupbox korrekt dargestellt. Sprich es werden sämtliche Controls, mit Ausnahme des Form-Text, korrekt dargestellt. Deshalb beschrieb ich diese Möglichkeit weiter oben auch nur als “bessere” und nicht als “perfekte” Lösung. Warum der Titel des Forms nicht korrekt gerendert wird, kann ich mir auch nicht erklären.

 

Ich hoffe ich konnte dem ein oder anderen von euch helfen. Standet ihr auch schon vor diesem Problem? Und wie habt ihr es gelöst? Kennt ihr vielleicht sogar eine bessere Lösung? Ich freue mich über jeden Kommentar!

Viele Grüße,
Raffi