ActiveDirectory mit C#
Donnerstag, 26. Mai 2011 14:33
Da ich für das aktuelle Projekt automatisierte Aufgaben innerhalb des ActiveDirectory realisieren muss, bin ich auf einen sehr guten Artikel bei Codeproject gestossen. Diesen will ich Euch nicht vorenthalten:

Codeproject - (Almost) everything in Active Directory via C#
von Timo Rehl | 1 comment(s)
Abgelegt unter:
Sharepoint 2010 Custom Masterpage
Montag, 9. Mai 2011 16:00

Sharepoint 2010 bietet nun endlich ein recht sauberes Design an, was Layout und Inhalt angeht. So ist es möglich über die Masterpage ein grundlegendes Layout für Sharepoint Seiten zu hinterlegen. Wie das geht, das zeigt nun folgende Anleitung.

Schritt 1 - Duplizieren der vorhandenen Masterpage

Die Masterpage dupliziert man am Besten über den Sharepoint Designer. Hierzu ruft man mit einem entsprechendem Designer Benutzer über die Startseite ->"Site Actions"->Sharepoint Designer auf.

Danach wählt man die Einstellungsmöglichkeit "Master Pages" und bekommt 3 bereits vorhandene Masterpages angezeigt:

Für Shareppoint 2010 ist die Masterpage v4.master relevant (Ausnahme: wenn die Kompatibilitätsfunktion SP2007 genutzt werden soll, dann wäre das der default.master). Es empfiehlt sich die Masterpage zu duplizieren, um so wenig Einfluss auf den SP2010 Standard zu nehmen. Das Duplizieren erreicht man durch Markieren des Originals, dann durch Auswahl von Copy (über das Kontextmenü oder über die Ribbon Leiste "Clipboard") und anschließendem Paste (analog zu Copy auffindbar). Es wird eine Kopie erstellt, die nun noch umbenannt werden kann (Kommando Rename über das Kontextmenü oder über die Ribbon Leiste "Edit").

Wo werden nun die Dateien abgelegt? -> Prinzipiell ist es nicht wichtig, ich komme im "Schritt 3 - Einbinden der neuen Masterpage" darauf. Es gibt hier 2 Unterscheidungen. Die Templates, die genutzt werden, sobald ein neues Sharepoint Portal angelegt wird befinden sich unter Windows:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\GLOBAL (englisches Betriebssystem!). Die duplizierte Masterpage befindet sich in der Sharepoint Datenbank (nicht auf Festplatte!).

Schritt 2 - Editieren der neuen Masterpage

Anschließend ist es möglich die neue Masterpage durch Auswahl des Kommandos EditFile (Ribbon Leiste "Edit") oder EditFile in advanced mode (Kontextmenü) zu editieren. Der "advanced mode" bedeutet hier lediglich, dass Sharepoint Standardeinstellungen im HTML Header ebenfalls editierbar sind. Ohne "advanced mode" kann man diese Stellen nicht verändern. Mein Ziel war es jQuery fest in allen Seiten verfügbar zu machen. Hierfür bietet SP2010 eine Möglichkeit über SciptLink das JavaScript einzubinden. Die genauen Details zum Thema ScriptLink werde ich nun hier nicht erläutern, Ziel hier ist es eine modifizierte Masterpage zu erzeugen.

Schritt 3 - Einbinden der Masterpage in Sharepoint-Seiten

Für das Einbinden der duplizierten Masterpage (bei mir heißt diese Arbeitsbereich.master) gibt es 2 Möglichkeiten:
  1. Man wählt die Website-Masterpage aus. Wie das geht kann man z.B. hier nachlesen: Mirjams Blog - Deploying a custom master page (im letzten Teil des Eintrages).
  2. Man verändert die Seiten direkt
Den 2. Punkt möchte ich näher betrachten, da das etwas flexibler ist, als Punkt 1. Zum manuellen Verändern der Masterpage folgt man folgender Anleitung:
  • Den Sharepoint Designer für die Webseite öffnen (siehe oben)
  • Die Auswahl "All Files" auswählen


Hier gibt es nun diverse Verzeichnisse, die man sich in Ruhe einmal anschauen sollte. Hier eine Kurzbeschreibung der wichtigsten Verzeichnisse:
- Site Pages: Enthält alle Webseiten, die in aller Regel auch navigierbar sind
- Lists and Libraries: Das sind alle Listen und Bibliotheken. Hier sind ebenfalls ASPX Seiten zu finden (!), für die Anzeige und Bearbeitung der Listen im Portal.
- Subsites: Hier sind alle Unterwebseiten zu finden

Für alle gefundenen ASPX Dateien kann man einzeln die Masterpage verändern. Hierzu wählt man entsprechende ASPX Datei aus und editiert diese im "advanced mode" (Kontextmenü). Für mein Besipiel habe ich unter SitePages/Home.aspx verwendet (Die Standardstartseite des Portals). Dort befindet sich in der ersten Zeile für die Parametrisierung der Codebehind Assembly auch das Attribut MasterPageFile. Diesen Attributwert kann man nun ändern:



Wichtig: Der Wert ~masterurl/default.master ist stark verwirrend für ASP.NET Programmierer. Zunächst lässt das ~masterurl vermuten, dass das analog der VirtualServerRoot ~ wäre (siehe Rick Strahls Blog - Making Sense of ASP.NET Paths). Dem ist aber definitiv nicht so. Es sind nur 2 verschiedene Werte mit ~masterurl fest verdrahtet, und somit nur "default.master" und "custom.master" möglich. Siehe hierzu auch nähere Informationen aus der MSDN - Customizing Master Pages.

Es gibt aber einen einfachen Trick für den Sharepoint Designer, der wohl aus VisualStudio übernommen wurde. Hierzu einfach den gesamten Wert mit einem zufälligen Buchstaben überschreiben, dann ermöglicht der Designer eine Kontextmöglichkeit Pick URL:

Das kann man bequem doppelklcken und dann komfortabel aus einem Verzeichnis wählen. Unsere duplizierte Masterpage liegt dann unter _catalogs/masterpage/Arbeitsbereich.master. Der Designer macht dann hieraus die URL: ../_catalogs/masterpage/Arbeitsbereich.master. Also auch bereits relativ zu der eigentlichen Seite, das ist sehr komfortabel, wenn die Seiten (ASPX Dateien) auf unterschiedlichen Hierarchieebenen liegen. Jetzt die Änderung noch speichern, diese sind dann auch sofort aktiv und können ausprobiert werden.

Schritt 4 - Fazit

Das Duplizieren und das Modifizieren der Masterpage ermöglicht dem Sharepoint Entwickler die Gestaltung eines einheitlichen Designs. Weiterhin können auch Skripte und allgemeine Funktionen über die MAsterpage bereitgestellt werden (so wie bei mir die Einbindung von jQuery). Es führen sicherlich 1000 Wege nach Rom, für mich war dieser Weg nun eine Möglichkeit globale Funktionalität bereitzustellen. Außerdem lernt man hierbei auch etwas die Struktur von Sharepoint kennen.
MS VPC - Deaktivieren der Zeitsynchronisation
Montag, 9. Mai 2011 15:52

Es gibt eine versteckte Möglichkeit bei Microsoft VPC die Synchronisation der Uhrzeit zwischen der virtuellen Maschine und dem Host zu unterbinden. Hierzu muss lediglich an entsprechender Stelle in der *.vmc Datei ein Eintrag platziert werden:

<preferences> 
 <integration> 
  <microsoft> 
   <components> 
    <host_time_sync> 
     <enabled type="boolean">false</enabled> 
    </host_time_sync> 
   </components> 
  </microsoft> 
 </integration> 
</preferences>

Natürlich sollte darauf geachtet werden, dass keine vorhandenen Knoten überschrieben, sondern nur ergänzt werden.

BizTalk 2010 Performance Optimization Guide
Montag, 14. Februar 2011 09:36
Microsoft hat für BizTalk 2010 eine Anleitung für die Konfiguration und Gestaltung von BizTalk und deren Applications veröffentlicht, um die Performance zu optimieren. Ich kann jedem BizTalk Entwickler diese Anleitung nur wärmstens empfehlen. Sie verrät auch etwas über die Stellschrauben von BizTalk und deren Auswirkungen.

Siehe hier:
BizTalk 2010 Performance Optimization Guide
BizTalk Terminator Tool
Montag, 14. Februar 2011 09:22
Microsoft hat ein sehr nettes BizTalk Benutzertool veröffentlicht. Ich kann das nur jedem BizTalk Entwickler und Admin ans Herz legen.

Zitat Microsoft:
***********
The BizTalk Terminator tool was created by the BizTalk support team to give BizTalk administrators the ability to easily correct many of the common database integrity issues. The BizTalk Terminator tool also provides a facility for tuning some performance settings and viewing certain key system counters.

The Terminator makes changes to the BizTalk databases; which are crucial to BizTalk operations. Before running the Terminator, you must do the following:

    * Backup all BizTalk databases.
    * Stop all host instances, including isolated host instances.
    * Stop all BizTalk SQL Agent jobs (or stop SQL Agent).

This also means that you should BE CAREFUL with this tool. If you are unsure about what a task does or if it is right for your situation, read the Description and/or click the Help button. If you’re still unsure, do not run it – contact Microsoft support.
***********

Quelle:
MSDN - BizTalk Terminator Tool
Performance Probleme bei String.IndexOf
Samstag, 8. Januar 2011 13:38
Wir haben herausgefunden, dass es zwischen der Framework Version 2.0 und des FW 4.0 Veränderungen in der String.IndexOf Methode gegeben hat, die starken negativen Einfluss auf die Verarbeitungsgeschwindigkeit haben.

Folgender Codeschnipsel zeigt das Problem, das jeder selbst auch ausführen kann:
    private static void SearchPattern(string strPattern, string strSearchString)
    {
      int startIndex = 0;
      int contentIndex = strSearchString.Length - 1;

      while (startIndex < contentIndex && startIndex != -1)
      {
        startIndex = strSearchString.IndexOf(strPattern, startIndex);
        if (startIndex != -1)
          startIndex = startIndex + strPattern.Length;
      }
    }


Aufgerufen haben wir o.g. Code indem wir zunächst eine Textdatei mit ca. 400 KB in einen String gelesen hatten und nach einem bestimmten Pattern gesucht hatten.


.NET Version=2.0.0.0
.NET Version=4.0.0.0

string.IndexOf(s,i)
string.IndexOf(s,i)
#Iterationen 10
00:00:00.0950380
00:00:11.4375732
#Iterationen 100
00:00:00.9233692
00:01:58.5309650
#Iterationen 1000
00:00:09.1416552
00:20:59.8498171


Es ist deutlich zu erkennen, dass mit der FW Version 4.0 u.U. ein Faktor 14 herauskommt.

Was man per Reflector erkennen kann ist, dass die Methode IndexOf(string,int) an die Methode IndexOf(string,int,StringComparison) mit dem Wert StringComparison.CurrentCulture übergeben wird. Genau hier liegt der Performance Issue. Ruft man explizit mit StringComparison.Ordinal auf, so ergibt sich folgendes Ergebnis:
startIndex = strSearchString.IndexOf(strPattern, startIndex,StringComparison.Ordinal);



.NET Version=2.0.0.0
.NET Version=4.0.0.0

string.IndexOf(s,i,StringComparison.Ordinal)
string.IndexOf(s,i,StringComparison.Ordinal)
#Iterationen 10
00:00:00.0225000
00:00:00.0200000
#Iterationen 100
00:00:00.2380000
00:00:00.2005000
#Iterationen 1000
00:00:02.0960000
00:00:02.0290000

Hier sind also Verschlimmbesserungen in der Kategorie Mehrsprachigkeit eingeflossen.

Das Ganze haben wir bereits Microsoft gemeldet und haben auch kurzfristig einen Fix zum Ausprobieren dafür bekommen. Der Fix hat gegriffen und wird in einen der nächsten .Net FW Updates mit einfließen (wenn nicht bereits erfolgt).

Sollte hier die String.IndexOf Methode in Verarbeitungsgeschwindigkeit-Relevanten Bereichen verwendet werden, so sollte darauf geachtet werden, dass vorsichtshalber das StringComparison.Ordinal (oder ein entsprechener Optionsparameter) hinzugefügt wird.
Rehl Factory - eine Singleton Instanz
Montag, 26. Juli 2010 20:10
Die Rehl Factory hat eine Singleton Instanz in die Welt gesetzt:

using System;

/// <summary>
/// Die wunderbare und einzigartige Struktur einer atemberaubenden Singleton.
/// Partial deshalb, weil die Klassendefinition immer mehr und mehr erweitert
/// werden wird.
/// </summary>
public partial class Bianca
{
    /// <summary>
    /// Die einzigartige Instanz.
    /// </summary>
    private static Bianca m_EinzigartigeBianca = new Bianca();

    /// <summary>
    /// Bianca gehört zur Rehl Family und es kann nur über die
    /// Singleton Instanz auf sie zugegriffen werden.
    /// </summary>
    private Bianca()
    {
    }

    /// <summary>
    /// Liefert den Zustand, ob Bianca hungrig ist.
    /// </summary>
    public bool IstHungrig
    {
        get { return GetWunderlicheAntwortObHungrig(); }
    }

    /// <summary>
    /// Liefert den Zustand, ob Bianca gerade schläft.
    /// </summary>
    public bool SchlaeftGerade
    {
        get
        {
            return (!IstHungrig && AugenZu && GleichmaessigeAtmung);
        }
    }

    /// <summary>
    /// Die wunderliche Antwort auf die Frage, ob Bianca hungrig ist
    /// liefert nur die Singleton Instanz mit Hilfe von inneren Zuständen,
    /// die on außen nicht einsehbar sind.
    /// (Trotz .Net und Reflection keine Chance ;-)
    /// </summary>
    /// <returns>True, wenn hungrig, andernfalls False.</returns>
    private bool GetWunderlicheAntwortObHungrig()
    {
        // Miracle, obscure and strange code here
    }
}


Mal schauen, was für Extension Methods sie noch bekommt. Unklar ist auch, wie die künstliche Intelligenz die Internen Datenströme wandern lässt. Und par tout hat sich noch nicht aller Code entschlüsseln lassen, trotz Refector (Ultraschall), oder genauerer Analyse. Ein Debuggen war leider nur von außen möglich. Die Factory und auch die Helferinstanzen (Ärzte) sind sich aber einig, sie lebt und sie ist gesund ;-)

Ich habe in den embedded Ressourcen noch ein Bild gefunden:


Die ist ja soo goldig ;-)))
BizTalk2010 - Host Instanz hält einen Eintrag in der MessageBox
Donnerstag, 22. Juli 2010 07:51
Wir haben mit den Tests unter BizTalk2010 festgestellt, dass die MessageBox nicht von Grund auf leer ist. Eine Rückfrage bei der Microsoft Produktgruppe hat ergeben, dass wohl eine Host-Instanz einen internen Eintrag in der MessageBox vornimmt. Der Eintrag ist keiner Service- bzw. Messageinstanz zuzuordnen.

Siehe auch Microsoft Connect.

Das "Schlimme" daran ist, dass selbst eine WMI Abfrage "SELECT * FROM MSBTS_MessageInstance" diesen internen Eintrag zurückliefert, und das glaube ich nicht, dass das "ByDesign" ist. Wir werden da nachhaken.
von Timo Rehl | 1 comment(s)
Abgelegt unter: ,
MSSQL Server alle Tabellen- und Spaltennamen aufisten
Samstag, 10. Juli 2010 14:03
Wer die komplette Struktur einer Datenabank einmal ausgeben lassen möchte, der kann das mit folgenden SQL Zeilen sehr schnell realisieren:
SELECT SysObjects.[Name] as TableName, SysColumns.[Name] as ColumnName, SysTypes.[Name] As DataType, SysColumns.[Length] As Length
FROM SysObjects
INNER JOIN SysColumns ON SysObjects.[Id] = SysColumns.[Id]
INNER JOIN SysTypes ON SysTypes.[xtype] = SysColumns.[xtype]
WHERE SysObjects.[type] = 'U'
ORDER BY SysObjects.[Name]
VisualStudio Debug Visualizer für Dictionary
Freitag, 9. Juli 2010 14:04
Dieser Artikel wurde zum 1. Mal am 09.07.2010 upgedatet

Ich habe nun sehr oft das Problem, dass ich in VisualStudio in einer Debug Session den Inhalt eines Dictionaries mir anzeigen, oder gar verändern möchte. Dictionaries sind bei mir recht häufig als Übergabeparameter definiert.

Was sind "Debug Visualizer"?

Debug Visualizer kennt jeder (aber wahrscheinlich nicht mit dem Begriff ;-). Ein berühmtes Beispiel ist der String-Visualizer:



Ich habe nun für VisualStudio 2005 und 2010 einen eigenen Visualizer für Dictionaries geschrieben.

Dictionary Visualizer Solution Aufbau:


Ein eigner Visualizer ist grundsätzlich vom Aufbau her immer gleich:
- Der Visualizer ist eine Class Library
- Es existiert eine Einstiegsklasse, die vom VS Debugger aufgerufen werden kann
- Es gibt ein Datenobjekt, das der Debugger zum (de-)serialisieren verwendet
- In der AssemblyInfo stehen die Informationen, damit VS weiß, welche Objekte mit dem Visualizer angezeigt werden können

In meinem Beispielprojekt ist das so aufgeteilt:
- DictionaryVisualizer.cs => Einstiegsklasse, die von der abstrakten Klasse DialogDebuggerVisualizer abgeleitet ist
- DictionarySource.cs => Die Datenklasse, von VisualizerObjectSource abgeleitet
- frmDictionaryVisualizer.cs => Das anzuzeigende Dialogfenster (äußerst trivial gehalten ;-)
- DataTableConverter.cs => Hilfsklasse, die Konvertierungen von und zu DataTables realisiert

Beschreibung der einzelnen Bestandteile:

DictionaryVisualizer.cs:

    /// <summary>
    /// Visualisiert ein Dictionary in einer Debug Session.
    /// </summary>
    public class DictionaryVisualizer : DialogDebuggerVisualizer
    {
        /// <summary>
        /// Zeigt einen modalen Dialog, das den Inhalt des Dictionaries visualisiert.
        /// </summary>
        /// <param name="windowService">Der Windows Context, in dem der Debugger läuft.</param>
        /// <param name="objectProvider">Das Dictionary-Objekt, das visualisiert werden soll.</param>
        protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
        {
            IDictionary dictToShow = null;
            
            // Versuchen, das Objekt aus dem Debugger zu extrahieren
            try
            {
                dictToShow = objectProvider.GetObject() as IDictionary;
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    String.Format("Folgender Fehler ist aufgetreten:\n{0}\nStack:\n{1}", ex.Message, ex.StackTrace),
                    "Fehler",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);

                // Fehler werden ausgegebenund weitere Schritte werden ignoriert
                dictToShow = null;
            }

            // Dictionary anzeigen lassen
            if (dictToShow != null)
            {
                using (frmDictionaryVisualizer dialog = new frmDictionaryVisualizer())
                {
                    dialog.Data = DataTableConverter.ConvertFromDictionary(dictToShow);
                    windowService.ShowDialog(dialog);
                    objectProvider.ReplaceObject(DataTableConverter.ConvertToIDictionary(dialog.Data, dictToShow.GetType()));
                }
            }
        }
    }

Die Methode Show wird vom Debugger ausgeführt, wenn auf die Lupe gedrückt wird (siehe TextVisualizer-Bild oben). Der Ablauf ist Straight-Forward:
- Zunächst wird versucht das eingehende Objekt aus dem objectProvider in ein IDictionary Objekt zu casten
- Sollte das geklappt haben, so wird aus dem Objekt ein DataTable Objekt konvertiert und dem Dialog übergeben
- Ist der Dialog zurückgekehrt, so wird dessen DataTable in ein neues Dictionary des gleichen Typs gewandelt und dem Debugger zurückgegeben

DictionarySource.cs:

    public class DictionarySource : VisualizerObjectSource
    {
        public override void GetData(object target, System.IO.Stream outgoingData)
        {
            IDictionary dictToSerialize = target as IDictionary;
            if (dictToSerialize != null)
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(outgoingData, dictToSerialize);
            }
        }
    }

Ebenfalls sehr einfach gestrickt. Hier wird die Methode GetData überschrieben, damit eine eigene Serialisierung des IDictionary Objektes stattfinden kann. Das ist quasi nur ein BinaryFormatter Wrapper.

AssemblyInfo.cs:

Hier ist es wichtig, dass über Attribute definiert wird, welche Objekte für einen Visualizer überhaupt in Frage kommen. Das definiert sich folgendermaßen:
[assembly: System.Diagnostics.DebuggerVisualizer(typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionaryVisualizer),
           typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionarySource),
           Target = typeof(System.Collections.DictionaryBase),
           Description = "Visualize IDictionary")]
[assembly: System.Diagnostics.DebuggerVisualizer(typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionaryVisualizer),
           typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionarySource),
           Target = typeof(System.Collections.Hashtable),
           Description = "Visualize IDictionary")]
[assembly: System.Diagnostics.DebuggerVisualizer(typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionaryVisualizer),
           typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionarySource),
           Target = typeof(System.Collections.Specialized.ListDictionary),
           Description = "Visualize IDictionary")]
[assembly: System.Diagnostics.DebuggerVisualizer(typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionaryVisualizer),
           typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionarySource),
           Target = typeof(System.Collections.Specialized.HybridDictionary),
           Description = "Visualize IDictionary")]
[assembly: System.Diagnostics.DebuggerVisualizer(typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionaryVisualizer),
           typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionarySource),
           Target = typeof(System.Collections.Specialized.OrderedDictionary),
           Description = "Visualize IDictionary")]
[assembly: 
System.Diagnostics.DebuggerVisualizer(typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionaryVisualizer),
          
 typeof(Rehl.DebuggingTools.DictionaryVisualizer.DictionarySource),
          
 Target = typeof(System.Collections.Generic.Dictionary<,>),
          
 Description = "Visualize IDictionary")]

Der Aufbau ist fast selbsterklärend. Der erste Parameter einer jeden Visualizer Definition ist der entsprechend aufzurufende Visualizer. In meiner ClassLibrary gibt es nur den einen DictionaryVisualizer. Der zweite Parameter bestimmt das Objekt, das zum (de-)serialisieren verwendet wird. Hier also auch immer wieder nur eines, nämlich das DictionarySource. Das Target definiert das Objekt, für welches der Visualizer gelten soll. In meiner Sammlung werden also DictionaryBase, Hashtable, ListDictionary, HybridDictionary und OrderedDictionary unterstützt.

Leider habe ich bis jetzt keine Möglichkeit gefunden generische Objekte hierfür definieren zu können. Wenn hier einer mehr weiß, dann kann er mir die Info gerne zukommen lassen, das wüde ich auch mit einbauen. Als Workaround kann man im Debugger ohne Probleme ein generisches Dictionary zu einem statischen casten und dnn die Visualisierung darauf laufen lassen.
Update: Inzwischen habe ich es herausgefunden, das war zu einfach ;-)

frmDictionaryVisualizer.cs und DataTableConverter.cs:
Auf diese beiden Bestandteile gehe ich jetzt nicht im Detail ein, das kann jeder nach Interesse selbst in der Solution erforschen.

Installation des Visualizers:
1. Die Solution mit VisualStudio öffnen und einmal als Release durchkompilieren lassen.
2. Dann VisualStudio schließen
3. Die Rehl.DebuggingTools.DictionaryVisualizer.dll aus dem bin/release Ordner in das entsprechende VisualStudio Verzeichnis kopieren, bei mir wäre das z.B. D:\Program Files\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\Visualizers
4. VisualStudio neu starten

Anwendung des Visualizers:
Sollte das Kompilieren und Kopieren abgeschlossen sein, so befindet sich in meiner Solution ein Test Konsolenprojekt, das eine eigene HashTable befüllt und an eine Testmethode übergibt.
Es sollte ein Breakpoint an der Stelle
string s = "OnlyToStopDebugger!";
gesetzt werden und dann Debugging des Projektes gestartet werden (wieder auf Debug umstellen nach einer Installation!).
Jetzt kann, wenn das Programm angahalten hat mit der Maus über den Übergabeparameter IDictionary data gefahren werden, und die Lupe erscheint. Sollte keine Lupe zu sehen sein, dann hat etwas mit der Installation nicht geklappt.
Ein Klick auf diese Lupe lässt das Dialogfenster erscheinen:


Jetzt lässt sich der Inhalt sortieren, und auch editieren.

Besonderes zu beachten:
Sollten eigene Dictionary Implementierungen verwendet werden, dann empfiehlt es sich von einem oben genannten Objekt abzuleiten. Weiterhin muss beachtet werden, dass das Serializable Attribut und eine Implentierung des Sonderkonstruktors für ISerializable vorhanden sin. In meiner Testapplikation wird das realisiert:
    [Serializable]
    public class InheritanceTestClass : Hashtable, ISerializable
    {
        public InheritanceTestClass()
            : base()
        {
        }

        public InheritanceTestClass(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
    }


Downlaod:
VS2005 Solution
VS2010 Solution
Mehr Beiträge Nächste Seite »