Montag, 19. Januar 2009

Versionskontrolle mit VisualSVN & AnkhSVN

Versionskontrolle ist sicherlich für jeden Entwickler ein Thema, vor allem natürlich im beruflichen Umfeld. Doch auch für die private Entwicklung ist sie ein Thema, denn auch hier möchte der Entwickler nicht auf die Sicherheit verzichten, die eine Versionskontrolle bietet. Nicht umsonst ist der Einsatz eines Versionskontrollsystems bereits für den ersten, den Roten Grad im Wertesystem der Clean Code Developer vorgesehen.

Aus genannten Gründen habe ich mich mit eben diesen Systemen auseinandergesetzt und mich letztlich für eine Kombination aus VisualSVN als Server und AnkhSVN als Visual Studio-AddIn entschieden. Dass beide kostenlos verwendet werden können, hat dabei natürlich auch eine Rolle gespielt.

Obwohl sich Installation, Einrichtung und Verwendung als denkbar einfach erweisen, möchte ich hier eine kleine Hilfe für den Einstieg bieten, die eventuell auch für Unentschlossene als kleine Entscheidungshilfe dienen kann.

Installation

Nachdem die beiden Installationsdateien für VisualSVN und AnkhSVN, die jeweils nur etwa 3 MB klein sind, heruntergeladen wurden, kann mit der Installation des Subversion-Servers begonnen werden. Man startet also zunächst die Installation von VisualSVN.

Die Installation gestaltet sich dabei als einfach. Lediglich in einem Fenster müssen Entscheidungen getroffen werden, die der Konfiguration des Servers dienen.

Konfiguration VisualSVN

Neben dem Installationsverzeichnis kann hier das Verzeichnis gewählt werden, in dem später die Repositories des Servers abgelegt werden.
Auch kann man den zu verwendenden Port einstellen und wählen, ob eine sichere Verbindung via https:// verwendet werden soll, um eine Verbindung mit dem Server herzustellen.
Schlussendlich bleibt noch die Wahl, ob man für den Zugriff separate Subversion-Benutzer verwenden möchte oder lieber die bereits existierenden Windows-Benutzer.

Der nebenstehende Screenshot zeigt die Standardeinstellungen, die ich für meine Installation auch so belassen werde.

Damit ist die Installation des Servers auch bereits abgeschlossen und er ist damit funktionstüchtig. Bevor wir uns jedoch genauer damit auseinandersetzen, installieren wir zunächst noch das Visual Studio-AddIn AnkhSVN, das uns als Client dienen wird. Diese beschränkt sich auf das Starten der Installation plus mehrmaliges “Weiter”-Klicken, daher gehe ich darauf nicht näher ein.

 

Konfiguration & Einrichtung

Nach erfolgreicher Installation starten wir zunächst den VisualSVN Server Explorer, den im Startmenü gefunden werden kann. Dieser dient der Verwaltung des Subversion-Servers. Hier werden beispielsweise Benutzer und Repositories angelegt, mit denen Subversion arbeitet. Auch kann hier der Server gestoppt und gestartet werden.SVN_002

Diese grundlegenden Einstellungen kann man direkt vom Startbildschirm aus treffen.
Wurde als Authentifizierungsmethode die Subversion-Authentifizierung gewählt, sollte zunächst ein Benutzer erstellt werden.
Anschließend wird noch ein Repository angelegt und schon ist die grundlegende Einrichtung erledigt und der Server einsatzbereit.

Bevor wir jetzt allerdings unser erstes Projekt unter Versionskontrolle stellen, möchte ich noch zeigen, wie man die Verwendung von Keywords bzw. Properties aktivieren kann.
Diese werden zur sogenannten Keyword Substitution benötigt. Dabei handelt es sich um die dynamische Ersetzung bestimmter Schlüsselwörter durch deren Werte innerhalb der Quelldatei. So kann man beispielsweise im Header der Quelldatei eine Übersicht realisieren, welcher Benutzer eine Datei zuletzt eingecheckt hat und wann dies geschehen ist.

Um Keywords zu aktivieren, navigieren wir zunächst zum Konfigurations-Verzeichnis des Subversion-Servers, der unter Windows XP unter “C:\Dokumente und Einstellungen\<Benutzername>\Anwendungsdaten\Subversion” zu finden ist.  Dort öffnen wir die Datei “config” mit einem beliebigen Editor.
In der Sektion [miscellany] muss zunächst die Zeile enable-auto-props = yes einkommentiert werden. Hierzu wird einfach die vorangestellte Raute entfernt.
Anschließend muss in der Sektion [auto-props] noch ein Eintrag für jede Datei-Art eingefügt werden, für die Keywords aktiviert werden sollen. Für C#-Quelldateien sieht der Eintrag folgendermaßen aus:

*.cs = svn:keywords=HeadURL LastChangedBy LastChangedRevision LastChangedDate Id

Wie hier zu sehen gibt es fünf Keywords, die aktiviert werden können. Diese haben teilweise noch Alias-Namen, die stattdessen verwendet werden können.
Um mehr über die Keywords und die Keyword Substitution an sich zu erfahren, kann unter http://svnbook.red-bean.com/en/1.4/svn.advanced.props.special.keywords.html nachgelesen werden.

Wichtig:
Soll Keyword Substitution verwendet werden, muss das beschriebene durchgeführt werden, bevor das Projekt , in dem sie verwendet werden soll, unter Source-Control gestellt wird.

 

Verwendung

Nun, da alles eingerichtet ist, können wir endlich dazu übergehen, unsere Subversion-Installation zu verwenden.
SVN_003

Wird jetzt in Visual Studio ein neues Projekt angelegt, zeigt sich eine Checkbox, die zuvor nicht verfügbar war. Diese erlaubt es, das zu erstellende Projekt direkt unter Source-Control zu stellen.

 

 

 

 

SVN_004

Wird diese Option ausgewählt, erscheint nach dem erfolgreichen Anlegen des Projekts ein Subversion-Dialog, in dem bestimmt werden kann, in welchem Repository es verwaltet werden soll.

Hier muss lediglich die URL des zu verwendenden Repositories eingefügt werden. Diese kann ganz einfach aus dem VisualSVN Server Manager kopiert werden.

Bei aktivierter Subversion-Authentifizierung kommt, muss sich der Benutzer nun zunächst anmelden.

Nach einem Klick auf OK steht das neu erstellte Projekt jetzt offiziell unter Versionskontrolle.

In Visual Studio wird man feststellen, dass einige neue Fenster hinzugekommen sind, ebenso wie einige Einträge ins Kontextmenü des Projektmappen-Explorers. Von entscheidender Bedeutung ist hierbei sicherlich das Fenster Pending Changes, dass anzeigt, welche Änderungen seit dem letzten Auschecken aufgetreten sind. Hier können diese Dateien auch wieder eingecheckt werden, was die Änderungen in das Versionskontrollsystem übernimmt.

Da wir uns so viel Mühe gegeben haben, die Keyword Substituation zu aktivieren, zeige ich jetzt noch, wie sie auch tatsächlich verwendet werden kann. Soll beispielsweise nach jedem Einchecken angezeigt werden, wann dies passiert ist und wer dafür verantwortlich zeichnet, fügt man in die Datei einfach einen Header ein, der wie folgt aussehen könnte.

   1:  // $LastChangedDate$
   2:  // $LastChangedBy$


Die Keywords, die enthalten sind, werden nun bei jedem Einchecken ersetzt und überschrieben, so dass der Header immer aktuell ist.

 

Jetzt wünsche ich viel Vergnügen beim Coden und Herumprobieren mit Subversion.
Sollten bei der Verwendung Fragen oder Probleme auftreten, kann das kostenlose Online-Buch Version Control with Subversion sicherlich wertvolle Dienste leisten.

Dienstag, 13. Januar 2009

DataBinding mit einer List<string>

Neulich stieß ich bei dem Versuch eine List<string> als Datenquelle für ein DataGridView zu verwenden auf ein interessantes Verhalten, das ich mir jedoch zunächst nicht erklären konnte.

Nehmen wir beispielsweise folgenden Code:

   1:  public FormMain()
   2:  {
   3:      this.InitializeComponent();
   4:   
   5:      List<string> tvStations = new List<string>();
   6:      tvStations.Add("Pro7");
   7:      tvStations.Add("RTL");
   8:      tvStations.Add("Sat1");
   9:      tvStations.Add("VOX");
  10:      tvStations.Add("Arte");
  11:      tvStations.Add("N24");
  12:      tvStations.Add("Phoenix");
  13:      tvStations.Add("RTL II");
  14:   
  15:      this.dgvTvStations.DataSource = tvStations;
  16:  }


Zu erwarten wäre, dass beim Start der Applikation unser DataGridView die in der Liste enthaltenen Fernsehsender anzeigt. Doch weit gefehlt, denn das Ergebnis sieht in Wirklichkeit so aus:

callingResult

Angezeigt werden uns also keineswegs die Fernsehsender sondern lediglich die Länge der Strings, die in der Liste enthalten sind.
Das liegt daran, dass die Datenquelle untersucht wird, wobei natürlich festgestellt wird, dass es sich um eine Liste von Strings handelt. Versucht man hier via Index auf einen bestimmten Wert zuzugreifen, wird man feststellen, dass die einzige verfügbare Eigenschaft dieses Wertes Length ist. Und genau diese wird dann vom DataGridView verwendet.

Um die Daten nun korrekt anzuzeigen muss ein Umweg in Kauf genommen werden.
Wir erstellen hierfür zunächst eine Klasse, die die Daten entgegennimmt, die wir anzeigen wollen. Im vorliegenden Fall könnte diese beispielsweise so aussehen:

   1:  public class TvStation
   2:  {
   3:      private string name;
   4:   
   5:      public string Name
   6:      {
   7:          get
   8:          {
   9:              return this.name;
  10:          }
  11:      }
  12:   
  13:      public TvStation(string name)
  14:      {
  15:          this.name = name;
  16:      }
  17:  }

 

Nun verwenden wir im Formular, das die Daten anzeigen soll, statt einer List<string> eine List<TvStation> und binden diese an den DataGridView.

   1:  public FormMain()
   2:  {
   3:      this.InitializeComponent();
   4:   
   5:      List<TvStation> tvStations = new List<TvStation>();
   6:      tvStations.Add(new TvStation("Pro7"));
   7:      tvStations.Add(new TvStation("RTL"));
   8:      tvStations.Add(new TvStation("Sat1"));
   9:      tvStations.Add(new TvStation("VOX"));
  10:      tvStations.Add(new TvStation("Arte"));
  11:      tvStations.Add(new TvStation("N24"));
  12:      tvStations.Add(new TvStation("Phoenix"));
  13:      tvStations.Add(new TvStation("RTL II"));
  14:      
  15:      this.dgvTvStations.DataSource = tvStations;
  16:  }

 

Wenn jetzt die Anwendung gestartet wird, zeigt der DataGridView tatsächlich die erwarteten Daten.

correctResult

Schade, dass in diesem Fall ein solcher Umweg nötig ist, aber so funktioniert DataBinding nun einfach mal.

Donnerstag, 11. Dezember 2008

Error: 0x80040204 - Invalid user auth.

Die im Titel stehende Meldung erhielt ich letztens beim lauf einer meiner Schnittstellen, die sich sequentiell durch Datensätze (in meinem Fall Accounts) eines CRM Systems per Webservice itteriert und darin automatisiert Änderungen durchführt.

Kleiner Fehler ganz groß. Als erstes wurde von allen (ausser mir ;) ) vermutet das sich der am CRM anmeldende User etwas erlaubt was ihm so nicht gestattet ist. Da ich diesen User aber bei allen Zugriffen benutze und alle anderen ja einwandfrei funktionierten, konnte ich das gleich ausschließen.
Meine Vermutung ging in Richtung des im Datensatz selbst zugewiesenen Systemuser (Owner) der bei jeder Änderung mit überegben wird. Dieser User ist ein auf der CRM Seite vorhandener Domänenuser und wird vom CRM System noch einmal extra als Entität "Systemuser" gehalten.
Meine Recherchen ergaben das man den Domänenuser aus der Domäne GELÖSCHT hatte, aber der User natürlich immer noch im CRM als Entität "Systemuser" vorhanden und bei vielen Datensätzen als Owner eingetragen war.
Durch die Löschung jedoch aus der Domäne hat der User praktisch alle rechte verloren und darf somit seine ihm zugeteilten Datensätze auch nicht mehr ändern.
Im vorliegenden Fall, hat die Firma in deren CRM das vorgekommen ist, in allen Datensätze mit einer Referenz zu dem rechtelosen User diesen durch einen in der Domäne noch aktiven User ausgetauscht. Damit hat dann wieder alles funktioniert.
CU TerA 

Freitag, 5. Dezember 2008

throw ex vs throw

Es ist eigentlich ein alter Hut, der Unterschied zwischen throw ex und throw sollte jedem bekannt sein. Throw ex schneidet den alten Stack Trace ab und verpackt sozusagen den Fehler neu, Throw hingegen nicht.

Aber dennoch halten sich irgendwie hartnäckig gegenteilige Meinungen, vermutlich aus den Gegenbenheiten aus Java resultierend, aber ich habe auch schon einige ellenlange Threads gelesen in denen das vollkommen Falsche dargelegt wurde, bis hin zu Projektleitern die von einem Verlangen ein ganzes Projekt umzuprogrammieren, weil sie der Meinung wären es wäre genau anders herum. 

Den Beweis zu führen ist recht simpel, entweder man schaut sich den MSIL Code an und erkennt das throw zu einem rethrow compiliert, während throw ex, ein throw ex bleibt. Oder aber man testet es einfach mit einem Programm folgender Art selber aus, um auch den letzten Kritiker hoffentlich verstummen zu lassen...

   1:  class ThrowVsThrowEx
   2:  {
   3:     static void Main(string[] args)
   4:     {
   5:        try
   6:        {
   7:           ReThrow();
   8:        }
   9:        catch(Exception ex)
  10:        {
  11:           Console.WriteLine("ReThrow sent: " + ex.ToString());
  12:        }
  13:   
  14:        Console.Write(System.Environment.NewLine);
  15:   
  16:        try
  17:        {
  18:           ThrowNew();
  19:        }
  20:        catch (Exception ex)
  21:        {
  22:           Console.WriteLine("ThrowNew sent: " + ex.ToString());
  23:        }
  24:   
  25:        Console.ReadLine();
  26:     }
  27:   
  28:     static void ReThrow()
  29:     {
  30:        try
  31:        {
  32:           DontCallMe();
  33:        }
  34:        catch
  35:        {
  36:           throw;
  37:        }
  38:     }
  39:   
  40:     static void ThrowNew()
  41:     {
  42:        try
  43:        {
  44:           DontCallMe();
  45:        }
  46:        catch(Exception ex)
  47:        {
  48:           throw ex;
  49:        }
  50:     }
  51:   
  52:     static void DontCallMe()
  53:     {
  54:        throw new ApplicationException("I said don't call me!!");
  55:     }
  56:  }


Ergebnis von throw:

ReThrow sent: System.ApplicationException: I said don't call me!! at DemoExceptions.ThrowVsThrowEx.DontCallMe() in C:\Projects\DemoExceptions\D emoExceptions\ThrowVsThrowEx.cs:line 54 at DemoExceptions.ThrowVsThrowEx.ReThrow() in C:\Projects\DemoExceptions\Demo Exceptions\ThrowVsThrowEx.cs:line 36 at DemoExceptions.ThrowVsThrowEx.Main(String[] args) in C:\Projects\DemoExcep tions\DemoExceptions\ThrowVsThrowEx.cs:line 7


und das Ergebnis von throw ex:

ThrowNew sent: System.ApplicationException: I said don't call me!! at DemoExceptions.ThrowVsThrowEx.ThrowNew() in C:\Projects\DemoExceptions\Dem oExceptions\ThrowVsThrowEx.cs:line 48 at DemoExceptions.ThrowVsThrowEx.Main(String[] args) in C:\Projects\DemoExcep tions\DemoExceptions\ThrowVsThrowEx.cs:line 18


Wunderbar zu erkennen wie throw ex den Ursprung abgeschnitten hat und stattdessen bei sich "selbst" anfängt... keine Worte :)

Montag, 10. November 2008

Konsole in Konsolenanwendung verbergen

Gerade hatte ich mal wieder eine "wie Schuppen von den Augen"-Situation.

Zielsetzung war, eine Konsolenanwendung zu erstellen, bei der die Konsole nicht sichtbar sein sollte.
Zuerst habe ich an etwas gedacth wie Console.Hide(), doch eine solche Methode existiert nicht.
Dann habe ich Google bemüht und seltsame Verrenkungen gefunden, die einen DllImport benötigten. Auch nicht gerade die feine Art, wie ich fand.

Und dann schoss es mir in den Kopf: Einfach den Ausgabetyp auf Windows-Anwendung setzen und glücklich werden!
Schon erstaunlich, wie einfach es manchmal sein kann und wie weit man dennoch daneben liegt...

P.S.: Gerade habe ich noch gesehen, dass in den Kommentaren des obigen Blog-Eintrags die von mir verwendete Möglichkeit tatsächlich auch von jemandem erwähnt wurde.

Donnerstag, 30. Oktober 2008

Toolbox-Item hinzufügen bei installierten Power Commands nicht möglich

Gerade eben wollte ich mir die Chart Controls für das .NET Framework 3.5 anschauen, die Microsoft vor kurzem veröffentlicht hat.
Leider war nach der Installation des Pakets nichts neues im Data-Tab der Toolbox zu finden. Laut Anleitung soll man für diesen Fall die Controls einfach händisch hinzufügen. Als ich das jedoch versuchte, fror mein Visual Studio 2008 einfach ein oder stürzte gar ab. Letzteres erfreulicherweise ohne jede Fehlermeldung.

Nach ein wenig Recherche habe ich tatsächlich herausgefunden, dass das Verhalten durch die installierten Power Commands für Visual Studio 2008 hervorgerufen wird.
Also habe ich diese schnell deinstalliert und siehe da, ich kann wieder Items zur Toolbox hinzufügen.

Sehr schade, dass die Power Commands einen derart negativen Einfluss auf VS2008 haben, denn eigentlich finde ich sie sehr nützlich. Deshalb werde ich sie auch wieder installieren und hoffen, dass ich mich das nächste mal, wenn ich etwas in die Toolbox schieben möchte, daran denke, sie zuvor zu deinstallieren.

Interessant ist im Übrigen auch, dass mein Kollege die Power Commands ebenfalls installiert hat, er jedoch problemlos neue Items in die Toolbox einfügen kann...

Nachtrag:
Ich habe die Power Commands jetzt wieder installiert und erneut versucht, ein Toolboxelement hinzuzufügen. Siehe da, es funktioniert einwandfrei.

Mittwoch, 29. Oktober 2008

Hexadezimaldarstellung eines Strings nach Int32 umrechnen - bbo-Style

Wie tropensturm Hex-Strings nach Int32 konvertiert, haben wir heute schon gelernt. Natürlich hat er gleich wieder Forderungen gestellt, also kommt hier meine Version.

Zunächst muss ich anmerken, dass ich wesentlich pragmatischer an die Sache herangegangen bin. Ich habe Dinge wie Encoding und Little- / Big-Endian vernachlässigt, denn ich brauchte schnell eine funktionierende Lösung für einen Test.

Folgender Code ist bei mir dabei heraus gekommen:

   1:  public static int ConvertHexStringToInt(string hexString)         
   2:  {
   3:      string hex = "0x";
   4:   
   5:      for (int i = 0; i < hexString.Length; i++)
   6:      {
   7:          hex += ((int)hexString[i]).ToString("X");
   8:      }
   9:   
  10:      return Convert.ToInt32(hex, 16);
  11:  }

Im Prinzip ist das, was ich hier tue, eigentlich recht einfach.
Zunächst lege ich mir eine String-Variable an, die die hexadezimale Darstellung des übergebenen Strings aufnehmen soll. In der for-Schleife sorge ich entsprechend dafür, dass dies auch so ist. In Zeile 7 wandle ich zunächst jeden Buchstaben des Übergabe-Strings in seine ASCII-Int32-Repräsentation, die anschließend nach Hexadezimal konvertiert und dem finalen String angehängt wird.
Ist die Schleife für alle Zeichen des Strings durchlaufen worden, haben wir einen String im Format 0xA9AE.
Diesen String konvertiere ich dann in Zeile 10 noch nach Int32, wobei ich eine Basis von 16 (also hexadezimal) angebe und gebe das Ergebnis zurück.

So weit, so einfach...
... leider aber auch so "beschränkt".
Durch das Konvertieren jedes Buchstabens in seine Int32-Repräsentation in Zeile 7 wird diese Lösung auf Zeichen beschränkt, die im ASCII-Zeichensatz vorhanden sind. Werden Zeichen verwendet, die in diesem nicht auftauchen, führt das zu falschen Ergebnissen.

FAZIT:
Für meine Zwecke ist diese Implementierung absolut ausreichend, da ich mir sicher sein kann, dass mein Übergabe-String nur Zeichen enthält, die auch im ASCII-Zeichensatz auftauchen. Für einen produktiven Einsatz ist aber auf jeden Fall tropensturms Lösung vorzuziehen, da diese eben auch mit nicht ASCII-konformen Zeichen umgehen kann.

bbo-Style: 0
tropensturm-Style: 1

Freie Cryptography API

Eine freie Cryptography API, inkl. OpenPGP, ohne jegliche Lizenzeinschränkungen mit der Ausnahme das License Informations File weiterzugeben. Hört sich zu gut an um wahr zu sein? :)

The Legion of the Bouncy Castle - Bouncy Castle Cryptography API

Features:
  • Generation and parsing of PKCS-12 files.
  • X.509: Generators and parsers for V1 and V3 certificates, V2 CRLs and attribute certificates.
  • PBE algorithms supported by PBEUtil: PBEwithMD2andDES-CBC, PBEwithMD2andRC2-CBC, PBEwithMD5andDES-CBC, PBEwithMD5andRC2-CBC, PBEwithSHA1andDES-CBC, PBEwithSHA1andRC2-CBC, PBEwithSHA-1and128bitRC4, PBEwithSHA-1and40bitRC4, PBEwithSHA-1and3-keyDESEDE-CBC, PBEwithSHA-1and2-keyDESEDE-CBC, PBEwithSHA-1and128bitRC2-CBC, PBEwithSHA-1and40bitRC2-CBC, PBEwithHmacSHA-1, PBEwithHmacSHA-224, PBEwithHmacSHA-256, PBEwithHmacRIPEMD128, PBEwithHmacRIPEMD160, and PBEwithHmacRIPEMD256.
  • Signature algorithms supported by SignerUtilities: MD2withRSA, MD4withRSA, MD5withRSA, RIPEMD128withRSA, RIPEMD160withECDSA, RIPEMD160withRSA, RIPEMD256withRSA, SHA-1withRSA, SHA-224withRSA, SHA-256withRSAandMGF1, SHA-384withRSAandMGF1, SHA-512withRSAandMGF1, SHA-1withDSA, and SHA-1withECDSA.
  • Symmetric key algorithms: AES, Blowfish, Camellia, CAST5, CAST6, DESede, DES, GOST28147, HC-128, HC-256, IDEA, ISAAC, NaccacheStern, Noekeon, RC2, RC4, RC5-32, RC5-64, RC6, Rijndael, Salsa20, SEED, Serpent, Skipjack, TEA/XTEA, Twofish and VMPC.
  • Symmetric key modes: CBC, CFB, CTS, GOFB, OFB, OpenPGPCFB, and SIC (or CTR).
  • Symmetric key paddings: ISO10126d2, ISO7816d4, PKCS-5/7, TBC, X.923, and Zero Byte.
  • Asymmetric key algorithms: RSA (with blinding), ElGamal, DSA, and ECDSA.
  • Asymmetric key paddings/encodings: ISO9796d1, OAEP, and PKCS-1.
  • AEAD block cipher modes: CCM, EAX, and GCM.
  • Digests: GOST3411, MD2, MD4, MD5, RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, Tiger, and Whirlpool.
  • Signer mechanisms: DSA, ECDSA, ECGOST3410, GOST3410, ISO9796d2, PSS, RSA.
  • Key Agreement: Diffie-Hellman and EC-DH.
  • Macs: CBCBlockCipher, CFBBlockCipher, GOST28147, HMac, ISO9797 Alg. 3, and VMPCMAC.
  • PBE generators: PKCS-12, and PKCS-5 - schemes 1 and 2.
  • OpenPGP (RFC 2440)
  • Cryptographic Message Syntax (CMS, RFC 3852), including streaming API.
  • Online Certificate Status Protocol (OCSP, RFC 2560).
  • Time Stamp Protocol (TSP, RFC 3161).
  • Elliptic Curve Cryptography (support for F2m and Fp curves).
  • Reading/writing of PEM files, including RSA and DSA keys, with a variety of encryptions. 
  • Hexadezimaldarstellung eines Strings nach Int32 umrechnen

    BBo hat mir eine Aufgabenstellung hingeworfen und wir haben diese dann unterschiedlich gelöst. Es ging darum die Hexadezimaldarstellung eines 2 Byte langen String nach Int32 zu konvertieren. Das war etwas schwieriger als wir dachten. Hier nun meine Lösungsvariante, vielleicht postet BBo ja noch seine ;)

    Das Erste was mir durch den Kopf ging ist, dass dies etwas gefährlich ist in Bezug auf das Stringencoding. Denn je nach dem wie der String decodiert wurde, hat man ja je nach Umgebung eine andere Hexadezimalwertdarstellung nach dem Encodieren. Darum habe ich einfach zur Absicherung das Encoding mit eingebaut in meine Lösung. Theoretisch kann man in einer homogenen Welt darauf verzichten, doch meine praktischen Erfahrungen in den letzten Monaten haben mir oft genug die Finger verkokelt. Man kann ja selber mal damit herumspielen und mit unterschiedlichen Encodings die unterschiedlichen Ergebnisse vergleichen...

       1:  // test
       2:  int erg = TwoByteStringHexValueToInt32("Aÿ", System.Text.Encoding.GetEncoding(1252));
       3:  ...
       4:   
       5:  public static int TwoByteStringHexValueToInt32(string input, Encoding encoding)
       6:  {
       7:     if (input.Length != 2)
       8:        throw new ArgumentException("TwoByteStringHexValueToInt32 - parameter input is allowed to be 2 byte long only!");
       9:              
      10:     if (encoding == null)
      11:        encoding = System.Text.Encoding.Default;
      12:   
      13:     int result = 0;
      14:     byte[] ba = encoding.GetBytes(input); // split to byte array of 2
      15:   
      16:     if (System.BitConverter.IsLittleEndian) // when little endian we need to do a workaround
      17:     {
      18:        result = (Convert.ToInt32(ba[0]) << 8) + Convert.ToInt32(ba[1]);
      19:     }
      20:     else
      21:     {
      22:        result = (int)System.BitConverter.ToInt16(ba, 0);
      23:     }
      24:   
      25:     return result;
      26:  }

    In Zeile 14 geht es richtig los, da zerleg ich den Input string in ein 2-Byte Array in Abhängigkeit (!) vom Encoding des Strings. 1252 ist das herkömmliche Encoding unter Windows für lateinische Schriftsysteme, u.a. Deutsch. Danach steht also in unserem Byte Array die Hexdarstellung unseres Strings.

    Danach mache ich einen kleinen Kunstgriff in Zeile 16, x86 Syteme sind LittleEndian kodiert, Motorola z.B. normalerweise BigEndian. Hier eine kleine Info wenn man damit nichts anfangen kann. Im Klartext, normalerweise rechnet man den Wert in unserem Bytearray wie in Zeile 22 gezeigt um. Mit dem Bitkonverter nach 16Bit Integer, werden 2 Bytes aus dem Bytearray ab der Position 0 gelesen und in Integer umgerechnet (Int32 bräuchte 4 Bytes, darum dieser Umweg).

    Und GENAU hier schlägt die Sache mit dem Little/Big Endian System zu! Denn wir haben zuvor oben unseren String eigentlich verkehrt herum abgelegt für unser x86 System!! Denn das rechnet von Hinten nach Vorne Bytedarstellungen nach Integer um!

    Daher das Byteshifting in Zeile 18, falls ein Little Endian System vorliegt. Ich greife mir das erste Byte konvertiere es nach Int32 und verschiebe es mal 8 Bits nach "links" (= 1 Byte, wir haben ja 2 Bytes und schieben das Erste sozusagen nach "vorne"), um dann einfach das Ergebnis aus der zweiten Byte Konvertierung dazu addieren.

    Nachtrag: Der Rückweg

       1:  public static byte[] Int16ToBigEndianByteArray(short input)
       2:  {
       3:     int higher = input >> 8;     // shift 1 byte -> get higher byte
       4:     int lower  = input & 0x00ff; // mask -> get lower byte
       5:   
       6:     byte[] ba = new byte[2];
       7:     ba[0] = Convert.ToByte(higher);
       8:     ba[1] = Convert.ToByte(lower);
       9:   
      10:     return ba;
      11:  }
      12:   
      13:   
      14:  ...
      15:  // test
      16:  byte[] ba = Int16ToBigEndianByteArray((short)31910);
      17:  string res = System.Text.Encoding.GetEncoding(1252).GetString(ba);

    Donnerstag, 16. Oktober 2008

    Embedded Ressources und ein bisschen mehr

    Dieser Blog entsteht aus einer Handvoll Diskussionen mit BBo über ein paar Tage hinweg. Irgendwie hab ich alle Punkte in ein Beispiel reingestopft bekommen :)

    Die Ursprungsfrage drehte sich darum, wie greift man auf eine eingebettete Ressource zur Laufzeit in meiner Assembly zu. Später kamen noch so Sinnesfragen hinzu wozu einen statischen Konstruktor, oder wie stell ich einfach fest ob die Konfiguration von log4net geklappt hat oder nicht,usw.

    Zur "embedded resource", als erstes hab ich eine XML angelegt, die einzig die Configurations Daten für Log4Net enthält. Ganz wichtig: unter Properties ist unter Build Action embedded resource auszuwählen, sonst finden wir das nachher nicht:

    Der Zugriff selber dann ist in Zeile 29 vom Code zu sehen. Beim auslesen der Ressource erhält man einen ganz normalen Stream, der kann dann wie gewohnt verarbeitet werden, log4net erlaubt uns eine Konfiguration direkt mit dem Stream. In Zeile 24 ist übrigens die Abfrage, ob Log4Net konfiguriert wurde, zu sehen.

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Text;
       4:  using System.Xml;
       5:  using System.IO;
       6:   
       7:  using Threading = System.Threading;
       8:  using Reflection = System.Reflection;
       9:  using L4N = log4net;
      10:   
      11:  namespace StaticLogWrapper
      12:  {
      13:      [Serializable]
      14:      public class Log
      15:      {
      16:          private static readonly L4N.ILog log = L4N.LogManager.GetLogger(typeof(Log));
      17:   
      18:          static Log()
      19:          {
      20:              // try configure the standard way
      21:              L4N.Config.XmlConfigurator.Configure();
      22:   
      23:              // is log4net configured? 
      24:              if (L4N.LogManager.GetRepository().Configured)
      25:                  return; // we are finished
      26:   
      27:              // when not set log4net config from internal setup
      28:              string name = "StaticLogWrapper.Log4NetConfig.xml";
      29:              Stream objStream = Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
      30:              L4N.Config.XmlConfigurator.Configure(objStream);
      31:              objStream.Close();
      32:          }
      33:          
      34:          ...