Zum Inhalt springen

Archiv

Tag: C#

Der Team Foundation Server bringt ein sehr nettes Feature mit, er informiert mich über bestimmte Änderungen per Email.
Finden tut ihr den „Alert Explorer“ in Visual Studio 2010 unter „Team“ -> „Alert Explorer“.

Alert Explorer Visual Studio 2010

Alert hinzufügen in Visual Studio 2010 Ich habe hier ein Alert auf meine Work Items und Tasks sowie wenn jemand bestimmte Dateien eincheckt. Möglich sind aber auch noch Meldungen über Builds.
Mit einem Klick auf „New Alert“ findet ihr Vorlagen für die verschiedenen Alert-Arten sowie einige vordefinierten Templates.
Wenn ihr eine Vorlage auswählt, seid ihr automatisch als Empfänger vorbelegt. Ihr könnt allerdings auch mehrere Benutzer informieren lassen. Der Name dient ledeglich zur Organisation im Alert Explorer, den Betreff oder den Inhalt der Emails kann man leider nicht weiter beeinflussen. Dies wäre durchaus praktisch um in Outlook spezielle Regeln greifen zu lassen.
Unterhalt der „Alert Definition“ werden die gewünschten Filterkreterien angegeben, hier mal ein Beispiel um mich über alle Änderungen an meinen Workpackages / Tasks / Bugs / etc. informieren zu lassen, die nicht ich gemacht habe.

Wer über Änderungen an Dateien informiert werden will, hat über den Source Control Explorer zusätzlich die Möglichkeit mit einem Rechtsklick auf die gewünschte Datei oder Ordner einen Alert zu erstellen. Hier bei wird nur eine Datei in die Alert Definition hinzugefügt. Markiert man mehrere Dateien im SCE, so bleibt der Punkt disabled. Allerdings kann man die Defintition logisch mit OR verknüpfen und so mehrer Dateien mit einer Defintition traken.

Meiner Meinung nach ein großartiges Feature. Nicht selten kommt es vor, dass Workpackages angelegt oder geändert werden, ich dies aber erst spät mitbekomme. Oder aber ich kann verfolgen, ob die Kollegen in den getrakten Dateien auch nur die Zeilen ändern, die sie ändern dürfen 🙂

Ich verstehe zwar nicht, warum es standardmäßig nicht im .NET Framework implementiert ist, allerdings ist es ohne Hilfsmittel nicht möglich, eine Klasse mit einem Dictionary mittels XmlSerializer zu serialisieren! Mit folgender Hilfsklasse funktioniert es dahin anstandslos, vorausgesetzt sowohl TKey und TValue sind Xml-serialisierbar.

using System.Collections.Generic;
using System.Xml.Serialization;

namespace Utilities.Generic
{
	[XmlRoot("dictionary")]
	public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
	{
		#region Constructors

		public SerializableDictionary():base() {}

		public SerializableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { }

		public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) {}

		public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }

		public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }

		public SerializableDictionary(int capacity) : base(capacity) { }

		#endregion

		private const string ItemTagName = "item";
		private const string KeyTagName = "key";
		private const string ValueTagName = "value";

		/// <summary>
		/// Diese Methode ist reserviert und sollte nicht verwendet werden. Wenn Sie die IXmlSerializable-Schnittstelle implementieren, sollten Sie null (Nothing in Visual Basic) von der Methode zurückgeben und stattdessen das <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> auf die Klasse anwenden, wenn ein benutzerdefiniertes Schema erforderlich ist.
		/// </summary>
		/// <returns>
		/// Ein <see cref="T:System.Xml.Schema.XmlSchema"/> zur Beschreibung der XML-Darstellung des Objekts, das von der <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/>-Methode erstellt und von der <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/>-Methode verwendet wird.
		/// </returns>
		public System.Xml.Schema.XmlSchema GetSchema()
		{
			return null;
		}

		/// <summary>
		/// Generiert ein Objekt aus seiner XML-Darstellung.
		/// </summary>
		/// <param name="reader">Der <see cref="T:System.Xml.XmlReader"/>-Stream, aus dem das Objekt deserialisiert wird.</param>
		public void ReadXml(System.Xml.XmlReader reader)
		{
			XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
			XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

			bool wasEmpty = reader.IsEmptyElement;
			reader.Read();

			if (wasEmpty)
			{
				return;
			}

			while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
			{
				reader.ReadStartElement(ItemTagName);

				reader.ReadStartElement(KeyTagName);
				TKey key = (TKey)keySerializer.Deserialize(reader);
				reader.ReadEndElement();

				reader.ReadStartElement(ValueTagName);
				TValue value = (TValue)valueSerializer.Deserialize(reader);
				reader.ReadEndElement();

				this.Add(key, value);

				reader.ReadEndElement();
				reader.MoveToContent();
			}
			reader.ReadEndElement();
		}

		/// <summary>
		/// Konvertiert ein Objekt in seine XML-Darstellung.
		/// </summary>
		/// <param name="writer">Der <see cref="T:System.Xml.XmlWriter"/>-Stream, in den das Objekt serialisiert wird.</param>
		public void WriteXml(System.Xml.XmlWriter writer)
		{
			XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
			XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

			foreach (TKey key in this.Keys)
			{
				writer.WriteStartElement(ItemTagName);

				writer.WriteStartElement(KeyTagName);
				keySerializer.Serialize(writer, key);
				writer.WriteEndElement();

				writer.WriteStartElement(ValueTagName);
				TValue value = this[key];
				valueSerializer.Serialize(writer, value);
				writer.WriteEndElement();

				writer.WriteEndElement();
			}
		}
	}
}

Den ursprünglichen Code habe ich hier her.

Update:
Habe die Klasse mal um die Standardkonstruktoren der Basis-Klasse erweitert um ein bestehendes Dictionary einfach umwandeln zu können.

Vielleicht haben sich schon einige von euch mit Lizenzen beschäftigt. Man erstellt eine Software, verkauft sie und möchte natürlich nicht, dass sie einfach von anderen kostenlos genutzt wird. Ich möchte daher heute eine Möglichkeit vorstellen. Sie ist recht simpel aber dennoch sehr flexibel gestaltet.

Um meinen Ansatz zu verstehen, muss man wissen, was eine asymmetrische Verschlüsselung funktioniert. Während bei einer symmetrischen Verschlüsselung mit einem Passwort sowohl ver- als auch entschlüsselt wird, gibt es bei der asymmetrischen Verschlüsselung zwei Schlüssel. Den Private und den Public Key. Während der Private und der Public Key verschlüsseln können, ist nur der Private Key in der Lage wieder zu entschlüsseln. Will man hingegen wissen, ob eine Nachricht wirklich vom Besitzer des Private Keys kommt, spricht man von Signierung. Signieren kann nur der Besitzer des Privaten Schlüssels, während jeder Public Key Besitzer dies verifizieren kann.

Dieses Verhalten kann man ausnutzen, der Hersteller der Software ist im Besitz des Private Keys und signiert Dateien, welche von der Software, welche den Public Key kennt, verifiziert. Sollte die Signatur nicht gültig sein, verweigert die Software ihren Dienst. Sollte jemand den Inhalt der Datei manipulieren, so muss sie wieder mit dem Private Key neu signiert werden.

Ich habe mir daher eine kleine, aber feine Klasse erstellt, welche entweder ein XML-Dokument oder eine Klasse, welche per XmlSerializer serialisierbar ist, signieren kann. So kann man theoretisch jede Information in eine XML-Lizenz-Datei hinterlegen, etwa wie lange die Lizenz gültig ist. Die nötigen Klassen befinden sich alle im .NET-Framework ab Version 2.0. Der Code ist zum Teil aus der MSDN (siehe Links am Ende des Beitrages).

Diese Möglichkeit bietet keinen absoluten Schutz. Leute könnten mit Programmen wie dotPeek an den SourceCode gelangen und die Prüfung ausbauen. Mit einem Obfuscator kann dies erschwert werden. Zudem dürft ihr niemals den privaten Schlüssel herausgeben, da dieser sowohl signieren als auch einen Public Key erstellen kann.

Beispielapplikation:

Hier findet ihr eine kleine Beispielanwendung. Die Form ist sehr trivial, erstellt erst die Keys, dann die Dummy-Klasse, signieren und zum Schluss validieren.

Links:

How to: Sign XML Documents with Digital Signatures
How to: Verify the Digital Signatures of XML Documents
Beispielanwendung

Ein kleiner Tipp für die Leute, die .NET Version 3.5 oder höher einsetzen:

Wer Text an Methoden / Klassen weitergeben will, die mit Streams arbeiten, sollte dies nicht umständlich über den MemoryStream lösen, sondern sich lieber mal die beiden Klassen StringReader und StringWriter anschauen. Geht deutlich einfacher und man braucht nicht umständlich mit irgendwelchen Encodings / Bytes / Stream-Positionen rumspielen.

Ich hatte ein recht umfangreiches Xml-Schema. Dieses wird ständig mal erweitert und eine andere Applikation benötigt nur einen Teil dieses Schemas. Dazu wurde es immer von Hand für die andere Applikation geändert. Um mir das Leben einfacher zu machen, wollte ich dies über eine XSLT-Transformation lösen, schließlich ist ein Schema auch nur eine XML-Datei. Ein großer Teil wurde einfach nur kopiert, dennoch sah die Ausgabe anders aus als die Eingabe. Mein Kopiertemplate sah folgendermaßen aus:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Einfach alle Nodes und Attribute kopieren, also nichts wildes. Dennoch wurde aus:

<xs:element name="comment" type="xs:string" minOccurs="0" />

folgendes:

<xs:element name="comment" type="xs:string" minOccurs="0"></xs:element>

Das Schema ist noch valide und funktioniert tadellos, nur sieht es nicht wirklich schön aus. Nachdem ich im Netz nach einen bestimmten Parameter im C#-Code und ähnliches gesucht hatte, wurde ich doch noch fündig. Das .NET-Framework bietet zwei verschiedene Methoden zur Transformation.
XslTransform und XslCompiledTransform. Der Kommentar in der MSDN sagt eigentlich alles:

Die XslCompiledTransform-Klasse ist ein XSLT-Prozessor, der die XSLT 1.0 Syntax unterstützt. Dies ist eine neue Implementierung, die im Vergleich zur veralteten XslTransform-Klasse die Leistung verbessert. Die Struktur der XslCompiledTransform-Klasse ist der XslTransform-Klasse sehr ähnlich.

Nebenbei werden auch noch das ShortEndTag unterstützt, womit mein Problem gelöst wäre. Der Vollständigkeit halber sollte noch auf diesen Blogeintrag hingewiesen werden: XslCompiledTransform Slower than XslTransform?, denn auch noch die veraltete XslTransform-Klasse scheint noch ihre Daseinsberechtigung zu haben.