# Friday, February 23, 2007

Inzwischen konnte ich das Service Pack 1 für den Team Foundation Server erfolgreich installieren. Eine der neuen Features ist die Möglichkeit externe Verbindungen zu dem Server zu ermöglichen.

Der TFS stellt seine Dienste über Web Services zur Verfügung. Mit dem Service Pack unterstützt er jetzt auch Basic und Digest Authentifizierung auf diesen Diensten. Bisher ging nur Integrated Windows Authentifizierung. Windows Authentifizierung geht aber nicht über das Internet. Jetzt ist aber zusammen mit HTTPS/SSL und den neuen Authentifizierungen der sichere externe Zugriff möglich.

Das liest sich ganz einfach und wie vom TFS gewohnt, ist die Implementierung nur für ganz Mutige: Walkthrough: Setting up Team Foundation Server with Secure Sockets Layer (SSL) and an ISAPI Filter

Mit den üblichen Zutaten:

  • Rumspielen in der Registry.
  • Editieren von Tabelleneinträgen mit dem SQL Server  Management Studio.
  • Ausführen von Programmen über die Shell.
  • Erstellen von Konfigurationsdateien mit Notepad.
  • Viel Herumklicken in diversen Management Konsolen.

Rootzertifikate kann man unter Vista x64 übrigens nicht mehr wie in dem Walkthrough beschrieben installieren. Über die CA Console direkt geht es aber.

Natürlich müssen alle beteiligten Firewalls den Zugriff erlauben, bzw. richtig weiterleiten. In unserem Fall also noch einmal ISA 2003 gefolgt von einmal Suse Linux mit iptables.

Schließlich hat es aber geklappt. Jetzt kann ich mit meinem neuen PC von zu Hause auf unsere Team Projekte zugreifen und fleißig weiter arbeiten. Muss ich jetzt ja auch, wenn ich vorher die ganze Zeit am TFS konfigurieren bin.

Friday, February 23, 2007 11:59:56 AM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 
# Thursday, February 22, 2007

Passiert mir nicht zu oft, dass ich auf größere Dienstreise gehe. Diesmal hat es mich in die USA verschlagen. Genauer nach New Jersey. Von dort hatte ich die Gelegenheit auch mal kurz durch New York zu schlendern.

Die Stadt vibriert zu jeder Tageszeit und ist immer wieder beeindruckend. Gerade am Times Square tummeln sich die Touristen und es flimmern zahllose Video-Leinwände und Werbebotschaften.

Zwischen Nasdaq und Yahoo hat Microsoft ein großes Plakat platziert. Mit der nicht so überzeugenden "Wow" Botschaft:

Pick a "Wow"

Any "Wow"

Vista Wow on Times Square

Noch mal vielen Dank an meinen Gastgeber Wolfgang Danspeckgruber. Ohne den geliehen Mantel wäre der Aufenthalt bestimmt unangenehmer gewesen: "Sonst holt dich noch der Eisbär". Es war doch kälter als erwartet.

Brooklyn Bridge

Als kleiner Abschluss noch die Statue of Liberty:

Statue of Liberty
Thursday, February 22, 2007 11:50:49 AM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 
# Wednesday, February 14, 2007

Mit dem Präfix clr-namespace kann man in XAML .NET Namespaces auf XML Namespaces mappen. Nur leider hat das bei mir nicht sauber funktioniert. Siehe auch XAML - clr-namespace - XamlParseException

Inzwischen habe ich das Problem genauer untersucht. Der XAML Parser versucht auf eine bestimmte Version der Assembly zuzugreifen: "Could not load file or assembly 'SPCatClient, Version=1.0.2596.20327...". Nur leider befindet sich zu dem Zeitpunkt bereits eine neuere Version im Debug Verzeichnis. Die Fehlermeldung ist also richtig. Aber wieso wird die Versionsnummer getestet? Die kann ja in diesem Fall gar nicht stimmen. Wahrscheinlich liegt es daran, dass ich alle Assemblies mit unserem CPTec Schlüssel signiere. Sie also strong-named Assemblies sind.

Die Lösung ist dann ganz einfach. Man muß nur bei den Projekteigenschaften, die automatische Nummerierung der Assembly Version abschalten. Standardmässig verwendet Visual Studio 2005 die Assembly Version "1.0*". Damit wird die Build Number und Revision Number automatisch bei jeder Compilierung erzeugt. Wenn man statt dessen eine feste Versionsnummer einträgt (z.B: 1.0.0.0), ist der XamlParser glücklich.

Assembly Information - Project Properties

Wednesday, February 14, 2007 10:46:42 AM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 
# Monday, February 12, 2007

Ich möchte Windows Forms und WPF Windows zusammen in einer Applikation verwenden. Jetzt ist mir aufgefallen, dass mein erster Ansatz noch nicht vollständig funktioniert: In den WPF Windows ist keine normale Tastatureingabe möglich!

Der Message Loop läuft im Windows Forms Kontext und da müssen wir die WPF Windows mit einklinken. Das geht dann doch nur über die Interop Assembly WindowsFormsIntegration. Also habe ich eine Referenz darauf zu dem Projekt hinzugefügt. Jedes WPF Window wird jetzt so geöffnet:

            Window1 window = new Window1();
            System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(window);
            window.Show();

ElementHost.EnableModelessKeyboardInterop() sorgt dafür, dass das übergebene Window alle Tastatureingaben von dem Windows Form Message Loop erhält.

Bis jetzt sieht alles gut aus.

Monday, February 12, 2007 5:33:28 PM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 

Auf THG (Tom's Hardware Guide) ist ein interessanter Artikel zur Datensicherung veröffentlicht worden. Unter anderem geht es darum, ob und wie es Sinn macht, auf Festplatten zu sichern: Band oder Speicherplatten? Moderne Backup-Produkte im Vergleich

Der Artikel ist etwas vorsichtig damit, externe Festplatten wirklich zu empfehlen. Ist auch verständlich, da die Gefahr eines Datenverlustes durch Beschädigung zu groß ist. Dank billiger Platten sollte man die Daten immer auf 2 Platten sichern und eine nicht transportieren. Mehr zu unserer Strategie haben wir hier dokumentiert: Backup-Software für Festplatten-Medien

Monday, February 12, 2007 1:16:36 PM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 
# Friday, February 09, 2007

Update: Inzwischen habe ich einen Workaround gefunden.

 

Ich möchte bei der Ausgabe das Datum gemäß den Benutzereinstellungen formatieren. Dazu habe ich einen DateTimeConverter geschrieben, der von IValueConverter abgeleitet ist. Dieses Objekt möchte ich natürlich an mehreren Stellen in der Applikation verwenden. Dann gehört das in die Application.Resources:

<Application x:Class="CPTec.SPCat.SPCatClient.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CPTec.SPCat.SPCatClient"

    Startup="AppStartup"
    Exit="AppExit"
    ShutdownMode="OnMainWindowClose"
    >
    <Application.Resources>
      <local:DateTimeConverter x:Key="dateTimeConverter" />
    </Application.Resources>
</Application>

Damit steht unter dem Key "dateTimeConverter" dieser Converter über zur Verfügung. Um Beispielsweise eine Tabellenspalte darüber darzustellen, ist folgende Definition möglich:

<GridViewColumn 
    DisplayMemberBinding="{Binding Path=LastUpload, Converter={StaticResource dateTimeConverter}}"
    Header="Last Upload" />

Bei der Datenbindung laufen damit alle Ausgaben über den DateTimeConverter und die Formatierung passt.

Das Problem ist nur, dass dieser Code nicht reproduzierbar funktioniert. Die meiste Zeit wirft das InitializeComponent() des Windows mit der ListView eine XamlParseException:

"Could not load file or assembly 'SPCatClient, Version=1.0.2596.20327, Culture=neutral, PublicKeyToken=af25da8d2987a9b1' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) Error in markup file 'SPCatClient;component/app.xaml' Line 11 Position 8."

Durch Neustart von Visual Studio und wildem "Rebuild Solution" funktioniert es dann wieder. Nur um dann im nächsten Versuch wieder über die gleiche Stelle zu stolpern.

Soweit ich das verstehe, muss ich bei der Definition xmlns:local="clr-namespace:CPTec.SPCat.SPCatClient" keine Assembly eingeben, wenn ich mich in genau dieser Assembly befinde. Aber irgendwas verknotet sich da. Im Moment ist das Ganze wieder auskommentiert. Das sollte aber nicht so bleiben.

Friday, February 09, 2007 11:48:05 AM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 
# Thursday, February 01, 2007

 Hurra! Hurra! So ein schöner Dialog:

Und nochmals Hurra!

Wieso die ganze Aufregung? Bisher ist jeder Versuch, dieses Service Pack zu installieren gescheitert. Die Wiederherstellung des Servers war beim ersten Versuch auch nicht gerade einfach. Bei allen weiteren Versuchen hatte ich vorher ein Image der Festplatte angelegt. Das ging dann schon schneller.

Jetzt kam über WSUS ein Update für den SharePoint Portal Server. Nach den bisherigen Erfahrungen war mir das zu heikel. Über Nacht hatte ich wieder eine Sicherung der kompletten Platte durchgeführt. Wie zum Trotz installierte sich das Update aber ohne Probleme. Mutig wollte ich es noch mal mit dem Service Pack für den Team Foundation Server probieren.

Inzwischen hatte sich Microsoft des Feedbacks angenommen und den Fall geschlossen (der gemeldete Workaround ist jetzt von mir :). Denkste. Ging natürlich wieder nicht. Genau wie bei allen vorherigen Versuchen. Diesmal habe ich aber eine neue mögliche Lösung gefunden. Der Vorschlag stammt aus der Microsoft Forum:

Im Fehler Protokoll kommt folgender Eintrag vor:

Setting SQL Server database 'TFSWorkItemTracking' into single user mode...
User does not have permission to alter database 'TFSWorkItemTracking' or the database does not exist.
ALTER DATABASE statement failed.

Was der Installer nicht kann, kann vielleicht der Setup User? Also SQL Server Management geöffnet und folgenden Befehl ausgeführt:

ALTER DATABASE TFSWorkItemTracking SET SINGLE_USER

Das geht seltsamerweise. Noch mal das Service Pack anstoßen: Es klappt! Der obige Dialog ist Belohnung für viel Mühe.

Thursday, February 01, 2007 12:53:55 PM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 
# Wednesday, January 31, 2007

Im Moment bin ich ein bisschen irritiert, wie sich WPF unter die CultureInfo verhält.

Ich verwende ein englisches Windows XP und habe im Control Panel unter Regional Options die "Standards and formats" auf German gestellt. Unter Windows Forms hat das standardmäßig dazu geführt, dass z.B: das Datum deutsch formatiert wurde. Auch Office und andere Anwendungen respektieren diese Einstellung.

Jeder Thread hat unter anderem zwei Properties: CurrentCulture und CurrentUICulture.

CurrentCulture: Das ist die Eigenschaft die ich im Control Panel eingestellt habe und bestimmt, wie Ausgaben formatiert werden. Bei mir "de-DE".

CurrentUICulture: Das ist die Sprache des Betriebssystems und bestimmt welche Elemente aus den Ressourcen verwendet werden. Quasi die Übersetzung. Bei mir "en-US".

Unter WPF kriege ich aber bisher nur die CurrentUICulture zu sehen. In meinem Fall eben "en-US". Folglich ist auch das Datum falsch formatiert. Ich möchte, dass die Einstellungen im Control Panel honoriert werden. Also basteln wir einen DateTimeConverter:

using System;
using System.Windows.Data;
using System.Globalization;
using System.Threading;

namespace CPTec.SPCat.SPCatClient
{
    /// <summary>
    /// Kurze Datums+Zeit Darstellung. Verwendet CurrentCulture und nicht CurrentUICulture
    /// </summary>
    [ValueConversion(typeof(DateTime), typeof(String))]
    public class DateTimeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            DateTime date = (DateTime)value;
            return date.ToString("g", Thread.CurrentThread.CurrentCulture);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string strValue = value.ToString();
            DateTime resultDateTime;
            if (DateTime.TryParse(strValue, Thread.CurrentThread.CurrentCulture, DateTimeStyles.None, out resultDateTime))
            {
                return resultDateTime;
            }
            return value;
        }
    }
}

Die Klasse implementiert IValueConverter einem neuen Interface in .NET 3.0 das beim Data Binding die Konvertierung von dargestelltem Wert und gebundenem Wert in beide Richtungen erlaubt.

Das Datum wird gezielt mit dem IFormatProvider aus CurrentCulture und nicht CurrentUICulture formatiert.

Der DateTimeConverter soll in der ganzen Applikation zur Verfügung stehen, also kommt er zu den Application.Resources in App.xaml:

<Application x:Class="CPTec.SPCat.SPCatClient.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:test="clr-namespace:CPTec.SPCat.SPCatClient" 

    Startup="AppStartup"
    >
    <Application.Resources>
      <test:DateTimeConverter x:Key="dateTimeConverter" />
    </Application.Resources>
</Application>

Und so verwende ich diese Resource dann beispielsweise in einer GridViewColumn:

  <GridViewColumn Header="Last Upload" 
    DisplayMemberBinding="{Binding Path=LastUpload,
      Converter={StaticResource dateTimeConverter}}" />

Dabei ist LastUpload vom Typ DateTime.

Obwohl das sicher eine Lösung für das Problem ist, frage ich mich schon, wieso das sinnvolle Konzept der getrennten Einstellung von Sprache und Formatierung wieder verschwunden ist? Oder zumindest nicht standardmäßig so wie bisher funktioniert. Oder übersehe ich etwas?

Wednesday, January 31, 2007 5:38:34 PM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 

Hurra, auch dieses Blog verbrennt jetzt seine Einspeisung. Sprich ich nutze die Dienste von FeedBurner.

Der neue FeedBurner Feed steht unter: http://feeds.feedburner.com/cdeger zur Verfügung.

Die auffälligste Änderung ist das FeedFlare, das jetzt unter jedem Eintrag zu sehen ist. Mit all den wunderbaren, neuen sozialen Netzwerken :).

Wednesday, January 31, 2007 12:06:23 PM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  | 
# Friday, January 26, 2007

Die Benutzeroberfläche soll auf den Anwender reagieren, obwohl gerade über HTTP Daten von einem SQL Server geladen werden. Also wird diese Arbeit über einen Background Thread erledigt. Der Fortschritt und das Ende dieser Aufgabe soll natürlich dem Anwender dargestellt werden. Nur darf dieser neue Thread nicht auf die Elemente der Benutzeroberfläche zugreifen. Die gehört dem Thread, der sie erzeugt hat. Andere Threads dürfen da nicht ran. Das gilt sowohl für Windows Forms als auch für die Windows Presentation Foundation.

In Windows Forms haben dazu die Controls ein Property InvokeRequired, das angibt, ob man mit Invoke oder BeginInvoke in den UI Thread Kontext wechseln muss. Um das ganze zu Kapseln habe ich den Background Threads immer eine Referenz auf ein Control mitgegeben. Damit konnte die Callbacks wieder auf dem UI Thread stattfinden. Ist aufwendig und man hat in der Business Logik Referenzen auf UI Elemente.

Mit .NET 3.0 gibt es für WPF den Dispatcher und ein DispatcherObject. Damit wird die Kontrolle über den Thread Kontext vereinfacht. Man leitet seine Hintergrund-Arbeiter von DispatcherObject ab und kriegt die Möglichkeit für UI Thread Aufrufe quasi geschenkt.

Und jetzt das Angenehme: Dieser neue Dispatcher funktioniert mit Windows Forms auch. Es wird also nicht nur einfacher, sondern man muss nicht mit unterschiedlichen Methoden für jede UI Technologie arbeiten.

Friday, January 26, 2007 10:37:18 AM (W. Europe Standard Time, UTC+01:00)  #
  Disclaimer  |  Comments [0]  |