ALM Rangers

Verwenden des Clientobjektmodells von Team Foundation Server

Willy-Peter Schaub
Brian Blackman

In diesem Artikel stellen wir das Clientobjektmodell von Visual Studio Team Foundation Server (TFS) vor und legen das Fundament für eine neue Reihe von Visual Studio ALM Rangers-Artikeln, die sich auf praktische Anleitungen und bekannte Codierungsszenarien in TFS konzentrieren.

Die ALM Ranger sind eine Gruppe von Experten, die sich für die Zusammenarbeit zwischen Visual Studio-Produktgruppen, Microsoft Services und der MVP-Community (Microsoft Most Valuable Professional) einsetzen, indem sie fehlende Funktionen ansprechen, Hindernisse für die Annahme der Technologie beseitigen und Best Practices sowie Anleitungen veröffentlichen, die auf tatsächlichen Erfahrungen beruhen.

Visual Studio TFS ist die Grundlage für Application Lifecycle Management (ALM). Es ermöglicht Teams, Lösungen effektiv, sicher und gemeinsam zu planen, zu koordinieren, zu erstellen, auszuführen und zu speichern. Es sichert Produktivität und bringt ALM in die Reichweite von professionellen Softwareentwicklern, unabhängig davon, ob sie zu einem kleinen, mittelständischen oder großen Unternehmen gehören, mit einem formalen, agilen oder individuellen Prozess arbeiten oder als virtuelle oder eng gekoppelte Teams. In diesem Artikel stellen wir die grundlegenden Architekturkonzepte vor, die Sie für die Arbeit mit TFS und vor allem für eine Erweiterung seiner Funktionen kennen müssen.

Warum Erweiterbarkeit so wichtig ist

TFS enthält Möglichkeiten und Mechanismen für die Erweiterung und Verbesserung des Produkts mit neuen Funktionen. Diese ermöglichen es Ihnen, die TFS ALM-Lösung an Ihre Umgebung anpassen und TFS mit benutzerdefinierten Funktionen und Verhaltensweisen zu erweitern, die nicht im Standardprodukt enthalten sind.

TFS ist eine Multi-Tier-Lösung, auf die programmatisch unter Verwendung des entsprechenden Objektmodells zugegriffen werden kann. Wie in Abbildung 1 dargestellt, umfasst das Objektmodell ein Client- und ein Serverobjektmodell, die verwendet werden können, um die Client- bzw. Anwendungsebene zu erweitern. In diesem Artikel konzentrieren wir uns auf das Clientobjektmodell.

Visual Studio Team Foundation Server ArchitectureAbbildung 1: Architektur des Visual Studio Team Foundation Server

Obwohl ein direkter Zugriff auf die Webdienste oder die Datenebene technisch möglich ist, empfehlen wir, auf die TFS-Funktionen und Daten über die entsprechenden Objektmodelle zuzugreifen, wie in Abbildung 1 dargestellt.

Lassen Sie uns kurz einen Schritt zurückgehen und die Idee des TFS-Objektmodells und seiner Namespaces betrachten, auf die wir uns sowohl in diesem Artikel als auch im zugehörigen Beispielcode beziehen.

Das Objektmodell besteht aus einer Gruppe von Klassen, die logisch auf Namespaces verteilt sind und physisch auf eine Reihe von Assemblys. Das TFS-Clientobjektmodell ist ein allgemeiner Begriff, der für alle öffentlichen Klassen in Microsoft.TeamFoundation.*.dll-Assemblys steht.

Namespaces fassen TFS-Klassen und -Funktionen in ähnliche Einheiten zusammen. Stellen Sie sich dazu einen Aktenschrank vor: Jedes Regal ist ein Objektmodell. Jeder Ordner in jedem Regal ist ein Namespace, und der Inhalt jedes Ordners stellt die Klassen dar. Wie die Ordner in einem Aktenschrank ermöglichen es die Namespaces, Klassen zu kategorisieren und relevante Klassen einfacher und schneller zu finden.

Wir werden uns auf die ersten Schritte bei der Erstellung eines Clients konzentrieren, der das TFS-Objektmodell verwendet, um eine Verbindung zu den TFS-Webdiensten herzustellen. Die TFS-Dienste unterstützen spezifische Funktionen wie Versionskontrolle, Ereignisse und Nachverfolgung von Arbeitsaufgaben.

Einrichten einer Entwicklungsumgebung

Wir verwenden die Sprache C# und die Visual Studio-IDE. Sie können das Objektmodell auch mit anderen Sprachen und Umgebungen verwenden, wie etwa Windows PowerShell.

Die Verwendung des TFS-Clientobjektmodells erfordert derzeit eine Client-SKU-Installation (beispielsweise Team Explorer) auf dem Entwicklungscomputer. Zukünftig wird das TFS-Clientobjektmodell als eigenständige Clientinstallation zur Verfügung stehen.

Team Explorer ist in allen Editionen von Visual Studio enthalten, mit Ausnahme der Express-Edition. Nachdem Sie Visual Studio und TFS installiert haben, starten Sie Visual Studio, stellen eine Verbindung zu einem TFS-Server her und bestätigen, dass Sie CRUD-Rechte (Create, Read, Update, Delete) für Arbeitsaufgaben und Quellcodeverwaltung besitzen.

Für diesen Artikel und die meiste Entwicklungsarbeit haben wir einen öffentlichen virtuellen Computer (Virtual Machine, VM) von Brian Keller verwendet, der Mitglied im ALM Developer Evangelism Team von Microsoft ist. Die VM für die Visual Studio 2010-Version ist abrufbar unter bit.ly/VS2010RTMVHD, die für die Visual Studio 2012-Version unter aka.ms/VS11ALMVM. Wenn Sie diese VM herunterladen, sollten die Codebeispiele ohne Änderung funktionieren. Wenn Sie den Code mit einem eigenen Server verwenden, könnten einige Anpassungen erforderlich sein.

Um mit dem Beispielcode in diesem Artikel zu arbeiten, benötigen Sie Verweise auf die später genannten TFS.NET Framework-Assemblys. Sie erhalten diese Assemblys bei der Installation von Team Explorer.

Best Practices und Richtlinien

Bei der Entwicklung von Clientanwendungen mithilfe des TFS-Objektmodells sollten Sie die folgenden Richtlinien befolgen.

Verwenden Sie die TFS Client-API, obwohl die API die Webdienste aufruft. Der direkte Zugriff auf die Webdienstschnittstellen wird nicht offiziell unterstützt. Das TFS-Clientobjektmodell hilft bei der Authentifizierung, stellt die Kompatibilität mit mehreren Serverversionen sicher, erleichtert Identitätswechsel, Zwei-Faktor-Authentifizierung mit Clientanmeldeinformationen und eine Handvoll anderer Dinge, neben der Bereitstellung sauberer, hoher Abstraktionen für die Webdienstschnittstellen. Für einige Clients (z. B. eine App mit Ruby on Rails unter *nix) ist die Webdienstschicht die einzige Option. Wenn das auch für Sie zutrifft, lohnt sich ein Blick auf das Java-SDK (siehe bit.ly/irHxgm).

Verwenden Sie so oft wie möglich rekursive Operationen, statt jedes einzelne Element aufzuzählen. Zum Beispiel sollten Sie den Ordner löschen und nicht jede einzelne Datei. Diese Richtlinie unterstützt eine Regel, die wir damals von Don Box gelernt haben, in seiner TechEd-Sitzung in New Orleans, als er noch sehr lange Haare hatte und noch nicht für Microsoft arbeitete: "Netzwerkverkehr vermeiden". In seiner Sitzung ging es um Remoteprozeduraufrufe (RPCs). Damals wurde zwar C-Code verwendet, aber die Regel ist nach wie vor von Bedeutung. Netzwerkverkehr vermeiden! Einige Entwickler haben diese Regel noch nicht verinnerlicht oder sind gerade dabei – auf die harte Tour mit Kunden und Beratern, die über schlechte Performance im Netzwerk klagen.

Halten Sie sich an die Regel „Netzwerkverkehr vermeiden“, indem Sie nicht rekursive Operationen zusammenfassen und Download-URLs nur anfordern, wenn Sie sie benötigen. Im Beispielcode wird diese Leitlinie stellenweise ignoriert, um API-Funktionen vorzuführen.

Verwenden Sie beim Übergeben eines Pfads an eine API den Serverpfad anstelle des lokalen Pfads. Der Grund ist, dass der lokale Pfad in den Serverpfad übersetzt werden muss. Diese Übersetzung erfordert, dass der Arbeitsbereich des Anrufers identifiziert, die Zuordnung geladen, die richtige Zuordnung bestimmt wird und so weiter, bevor endlich der Serverpfad vorliegt.

Gehen Sie bei Ihren Operationen von optimistischen Voraussetzungen aus. Setzen Sie, ähnlich wie bei Datenbanken, bei einem Schreibvorgang den Erfolg voraus und fangen Sie eventuelle Fehler ab. Verschwenden Sie zum Beispiel bei der Verwendung der Versionskontrolle nicht wertvolle Zeit mit der Überprüfung des Elements, bevor Sie es verarbeiten, denn die Datei könnte gelöscht worden sein, sodass sowieso die Notwendigkeit besteht, Ausnahmen zu behandeln. Gehen Sie also vom Erfolg aus und berücksichtigen Sie den Misserfolg.

Ein nützliches Tool zur Ermittlung überflüssigen Netzwerkverkehrs ist Microsoft Network Monitor. Verwenden Sie dieses Tool und untersuchen Sie in Ihrem Code nicht selbst das Netzwerk. Kein Packet kann dieses Tool umgehen, um die Wahrheit zu verbergen. Sie können Microsoft Network Monitor auf den Microsoft-Downloadseiten (bit.ly/mMmieH) herunterladen.

Sofern Sie nicht mehr überblicken, warum, auf welche Weise oder wie lange ein Vorgang abläuft, sollten Sie die Nachverfolgung (Tracing) für Webmethoden aktivieren. Sie zeigt Ihnen, welche Webmethoden von der API aufgerufen werden. Zudem erhalten Sie Informationen über Ziel und Dauer eines Aufrufs sowie die SOAP-Antwort. Die Ablaufverfolgung wird durch eine Änderung der Datei application.config im Abschnitt system.diagnostics aktiviert, wie in Abbildung 2 dargestellt. Abbildung 3 zeigt ein Beispiel für eine Ausgabe in die Protokolldatei. Wenn Sie allerdings einen Blick auf die SOAP-Nutzlast werfen möchten, müssen Sie ein Tool wie Microsoft Network Monitor verwenden.

Abbildung 2: Aktivieren der Ablaufverfolgung in der Konfigurationsdatei

<?xml version ="1.0"?>
  <configuration> 
    <system.diagnostics>
      <switches>
        <add name="TeamFoundationSoapProxy" value="4" />
        <add name="VersionControl" value="4" />
      </switches>
      <trace autoflush="true" indentsize="3">
        <listeners>
          <add name="rangerListener"    
            type="Microsoft.TeamFoundation.TeamFoundationTextWriterTraceListener,
            Microsoft.TeamFoundation.Common, Version=10.0.0.0, Culture=neutral,
            PublicKeyToken=b03f5f7f11d50a3a"
            initializeData="c:\almrangertracing.log" />
          <add name="performanceListener" 
            type="Microsoft.TeamFoundation.Client.PerfTraceListener,
            Microsoft.TeamFoundation.Client, Version=10.0.0.0, Culture=neutral,
            PublicKeyToken=b03f5f7f11d50a3a" />
        </listeners>
      </trace>
    </system.diagnostics>
  </configuration>

Abbildung 3: Ablaufverfolgung und Leistungsdaten für eine Webmethode

03/17/2012 12:10:14 (pid 2936, tid 4820, 11636 ms) Web method response: [http://servername/tfs/myCollection/VersionControl/v1.0/repository.asmx] QueryWorkspace[VersionControl] 3 ms
03/17/2012 12:10:14 (pid 2936, tid 4820, 11637 ms) CreateWebRequest() -- Uri: http://servername:8080/tfs/myCollection/VersionControl/v1.0/repository.asmx
03/17/2012 12:10:14 (pid 2936, tid 4820, 11637 ms) request.AutomaticDecompression: GZip
03/17/2012 12:10:14 (pid 2936, tid 4820, 11637 ms) Web method running:
http:// servername:8080/tfs/myCollection/VersionControl/v1.0/repository.asmx] UpdateWorkspace[VersionControl]
03/17/2012 12:10:14 (pid 2936, tid 4820, 11658 ms) HTTP headers:
Content-Length: 896
Cache-Control: private, max-age=0
Content-Type: application/soap+xml; charset=utf-8
Date: Sat, 17 Mar 2012 16:10:12 GMT
Server: Microsoft-IIS/7.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET

Die Bedeutung der Assemblys und Namespaces

Das TFS-Objektmodell enthält viele Assemblys und Namespaces. In dieser Artikelserie werden nicht alle Assemblys behandelt, sondern nur die wichtigsten und am häufigsten verwendeten Namespaces. Neben den grundlegenden TFS-Namespaces berücksichtigen wir auch .NET Core-Namespaces, die bei der Verwendung des TFS-Objektmodells benötigt werden.

Eine übliche Vorgehensweise ist, die Verbindung zum Team Foundation Configuration Server oder einer Sammlung herzustellen und die registrierten Server oder Projekte aufzulisten. Für derartige Clientaufgaben sind folgende Verweise erforderlich: 

// Needed for TfsConfigurationServer
using Microsoft.TeamFoundation.Client;
// Needed for Catalog Resources such as types
using Microsoft.TeamFoundation.Framework.Common;
// Needed for other Catalog Resouces such as nodes
using Microsoft.TeamFoundation.Framework.Client;
// Needed for use of the Version Control service
using Microsoft.TeamFoundation.VersionControl.Client;

Für jeden der verfügbaren Dienste benötigen Sie ebenfalls diese Verweise, beispielsweise Microsoft.TeamFoundation.VersionControl.Client für die Versionsverwaltung. Zur Verwendung von Arbeitsaufgaben sind möglicherweise Verweise auf folgende Namespaces erforderlich:

  • Microsoft.TeamFoundation.WorkItemTracking.Client
  • Microsoft.TeamFoundation.WorkItemTracking.Common
  • Microsoft.TeamFoundation.WorkItemTracking.Proxy

Abbildung 4 zeigt die Hauptassemblys aus dem TFS-SDK, die Sie für TFS 2010 in Program Files\Microsoft Visual Studio 10.0\Common7\IDE unter ReferenceAssemblies\v2.0 bzw. PrivateAssemblies finden und in Program Files (X86)\ ... bei einem 64-Bit-Betriebssystem.

Abbildung 4: Assemblys im TFS-SDK

Namespace

o = Microsoft.TeamFoundation

Beschreibung
o.client Der Namespace und die zugehörigen Assemblys stellen die Schnittstellen bereit, die erforderlich sind, um eine Verbindung mit TFS herzustellen und um auf Daten im Zusammenhang mit Teamprojekten und Teamprojektsammlungen zuzugreifen.
o.framework.client Der Namespace und die zugehörigen Assemblys machen APIs verfügbar für: Anzeige und Verwaltung der Inhalte der TFS-Registrierung, Auftragsplanung, generische Eigenschaftenspeicher, Eventabonnements, Sicherheitsnamespaces, Dienste, Teamprojektsammlungen, Katalog- und Lab-Managementobjekte.
o.framework.common Der Namespace und die zugehörigen Assemblys definieren allgemeine Objekte wie Berechtigungen, Ausnahmen und Konstanten.

 (Hinweis: Das von uns bereitgestellte Standardcodebeispiel wurde erstellt und getestet mit dem freigegebenen TFS 2010-Objektmodell und den Assemblys unter …\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0. Wenn Sie das Objektmodell der neuen TFS 11-Betaversion verwenden möchten, müssen Sie die Microsoft.TeamFoundation.*-Verweise löschen und aus Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0 wieder hinzufügen. Anschließend erstellen Sie die Beispielanwendung erneut. Sie können beide Objektmodelle verwenden, um mit den Standardbeispielen eine Verbindung zu TFS 2010- und 2012-Servern herzustellen.)

Wenn Sie sich für die komplette Beispiellösung und weitere Codebeispiele der Visual Studio ALM Ranger interessieren oder selbst Beispiele beitragen möchten, besuchen Sie uns auf bit.ly/M0oyQt.

Unser erstes Programmierabenteuer

Wie sie bereits wissen, benötigen Sie zum Herstellen der Verbindung mit einem TFS-Server folgende Verweise:

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Framework.Client;

Für die Übergabe von Netzwerkanmeldeinformationen an einige überladene Methoden (wie im folgenden Codebeispiel) benötigen Sie einen Verweis auf den System.Net-Namespace:

NetworkCredential myNetCredentials =
  new NetworkCredential("Administrator", "P2ssw0rd");
ICredentials myCredentials = (ICredentials)myNetCredentials;

NetworkCredentials ist nützlich, wenn Sie die öffentliche TFS VM verwenden. Nachdem Sie die Verweise bezogen haben, gibt es mehrere Möglichkeiten für die Verbindung mit einem TFS-Server. Sie können eine Verbindung zum Konfigurationsserver herstellen und dort eine Liste von Sammlungen für Ihre Server-URI und die Anmeldeinformationen abrufen:

Uri tfsUri = @"http://servername:8080/tfs";
TfsConfigurationServer configurationServer =
  new TfsConfigurationServer(tfsUri, myCredentials);

Besser ist es, den Benutzer zur Eingabe der Anmeldeinformationen aufzufordern, indem Sie (wie im folgenden Beispiel) UICredentialsProvider übergeben:

TfsConfigurationServer configurationServer =
  new TfsConfigurationServer(tfsUri, new UICredentialsProvider());

Zweiter Ansatz – Verbinden mit einem neuen Konfigurationsserver

Hier ist ein alternativer Ansatz, wenn Sie den Vorgang mit den erforderlichen Anmeldeinformationen ausführen und die Verbindung mit einem neuen Konfigurationsserver vermeiden möchten:

TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
// Once you have your connection then you can
// get a list of collections on the server
// Get the catalog of team project collections
ReadOnlyCollection<CatalogNode> collectionNodes;
collectionNodes = configurationServer.CatalogNode.QueryChildren(
  new[] { CatalogResourceTypes.ProjectCollection },
  false, CatalogQueryOptions.None);
foreach (CatalogNode collectionNode in collectionNodes)
{
  // Add each collection to the combo box
  cbTPC.Items.Add(collectionNode.Resource.DisplayName);
}

Das obige Beispiel setzt die Eingabe eines URI in einem Bearbeitungssteuerelement des Dialogfelds voraus. Im nächsten Beispiel werden wir die Liste der auf dem Client registrierten Server einlesen. Registrierte Server sind die TFS-Server, die in Visual Studio über das entsprechende Dialogfeld hinzugefügt worden sind, wie in Abbildung 5 dargestellt.

Registered Team Foundation Server Dialog Box
Abbildung 5: Dialogfeld für registrierte TFS-Server

Zum Auslesen der auf dem Client registrierten Server benötigen Sie einen Verweis auf Microsoft.TeamFoundation.Client. Im folgenden Code werden die registrierten Server ermittelt und (wie in Abbildung 6 gezeigt) einem ComboBox-Steuerelement hinzugefügt:

List<RegisteredProjectCollection> registeredTPCs;
// Get all registered collections on this machine
registeredTPCs = new
  List<RegisteredProjectCollection>((
    RegisteredTfsConnections.GetProjectCollections()));
foreach (var projectCollection in registeredTPCs)
{
  // Add each registered team project collection to the combo box
  cbRegColl.Items.Add(projectCollection.Uri);
}

Reading Registered Servers
Abbildung 6: Ermitteln der registrierten Server

Dritter Ansatz – Verbinden mit einem bekannten Sammlungs-URI

Wenn Sie den URI der Sammlung kennen, können Sie damit eine direkte Verbindung herstellen. Abbildung 7 zeigt diesen dritten Ansatz – Verbinden mit einem bekannten Sammlungs-URI.

Abbildung 7: Verbinden mit einem bekannten Sammlungs-URI

NetworkCredential myNetCredentials =
  new NetworkCredential("Administrator", "P2ssw0rd");
ICredentials myCredentials = (ICredentials)myNetCredentials;
// Connect to the tpc hosting the version-control repository
TfsTeamProjectCollection tpc =
  new TfsTeamProjectCollection(new Uri(cb.Text),
  myNetCredentials);
// Get the version control service
vcServer = tpc.GetService<VersionControlServer>();
var teamProjects =
  new List<TeamProject>(vcServer.GetAllTeamProjects(false));
// List the team projects in the collection and add to list box
foreach (TeamProject projectNode in teamProjects)
{
  // Add list or team projects to list box
  lbProjects.Items.Add(projectNode.Name);
}

Die nächsten Beispiele zeigen die Verwendung einiger Funktionen der Versionskontrolle. Wenn Sie über die Verweise zum Server und einen Verweis zum Dienst der Versionskontrolle verfügen (siehe Abbildung 7), können Sie einige der APIs verwenden, um beispielsweise eine Dateiliste vom Server oder anstehende Änderungen abzurufen. Der folgende Code verwendet den Serververweis für die Versionskontrolle, um Informationen über alle XAML-Dateien auf dem Server abzurufen und sie in einem ListBox-Steuerelement einzutragen:

// List all of the XAML files on the server
ItemSet items = vcServer.GetItems("$/*.xaml", RecursionType.Full);
foreach (Item item in items.Items)
{
  // Add each file to the list box
  lbAll.Items.Add(item.ToString());
}

Der erste Parameter für die GetItems-Methode ist der Pfad zum Ordner. Im Beispielcode wird der Pfad zum Wurzelverzeichnis übergeben, sodass die XAML-Dateien aus allen Ordnern zurückgegeben werden. In Abbildung 8 sehen Sie, dass bei der Auswahl einer Datei Informationen über die Datei angezeigt werden.

Get All XAML Files and Show File Details
Abbildung 8: Abrufen aller XAML-Dateien und Anzeigen von Dateiinformationen

Mit dem in Abbildung 9 dargestellten Code rufen Sie eine Liste von Dateien ab, für die Änderungen anstehen, und tragen sie in ein ListBox-Steuerelement ein. In diesem Code ist die API QueryPendingSets überladen. Im Beispiel wird diejenige Methodenüberladung verwendet, die Abfragen mit ItemSpecs erlaubt, einem Array, das die abzufragenden Elemente enthält. In diesem Fall fragen wir nach anstehenden Änderungen in nur einem Ordner auf dem Server. Außerdem beschränken wir die Abfrage auf anstehende Änderungen für einen bestimmten Arbeitsbereich und Benutzer. Im letzten Parameter wird die API angewiesen, die Informationen bereitzustellen, damit wir die Datei herunterladen können. Wenn Sie diese Informationen nicht benötigen, halten Sie sich an die Regel „Netzwerkverkehr vermeiden“ und übergeben "false".

Abbildung 9: Anstehende Änderungen abrufen

ItemSpec[] itemSpecs = new ItemSpec[1];
// You can filter the path to a project and folder
// using $/ProjectName/Folder...
ItemSpecs[0] =
  new ItemSpec(@"$/Tailspin Toys/Development/Iteration 2",
  RecursionType.Full);
// Your options for filtering are the Workspace Name,
// User Name and the previous path in the ItemSpec
String qryWSName = @"WIN-GS9GMUJITS8";
String queryUserName = @"administrator";
bool includeDownloadInfo = true;
PendingSet[] pendingSet = vcServer.QueryPendingSets(
  itemSpecs, qryWSName, qryUserName, includeDownloadInfo);
foreach (PendingSet ps in pendingSet)
{
  // Add pending changes to list box
  lbPendingChanges.Items.Add(ps.ToString());
}

Die Versionskontrolle umfasst noch viele weitere Funktionen, die dieser Artikel nicht behandelt. Wir haben versucht, Ihnen Appetit zu machen und Sie zu ermuntern, eine Verbindung mit dem Server herzustellen und den Dienst für die Versionskontrolle auszuprobieren.

In zukünftigen Artikeln werden wir auch weiterhin das TFS-Clientobjektmodell untersuchen und verschiedene Programmierszenarien vorstellen. Wir behandeln das Arbeiten mit Arbeitsaufgaben, die Versionskontrolle, den Erstellungsvorgang und widmen uns auch dem Visual Studio TFS-Serverobjektmodell.

Brian Blackman ist Principal Consultant im Microsoft Services Partner ISV-Team und arbeitet für den Erfolg der ISV-Partner in Engineering und im Markt. Er hat einen MBA-Abschluss und ist CSM, MCSD (C++), MCTS und Visual Studio ALM Core Ranger. Er verbringt seine Zeit damit, Code zu schreiben, Workshops zu erarbeiten und zu verbreiten, und ist Berater für ALM.

Willy-Peter Schaub ist Senior Program Manager bei den Visual Studio ALM Rangers im Microsoft Canada Development Center. Seit Mitte der 80er Jahre bemüht er sich um mehr Einfachheit und Instandhaltbarkeit in der Softwareentwicklung. Sie finden seinen Blog unter blogs.msdn.com/b/willy-peter_schaub. Folgen Sie ihm auf Twitter unter twitter.com/wpschaub.

Unser Dank gilt den folgenden technischen Experten für die Durchsicht dieses Artikels: Jeff Bramwell, Bill Essary, Mike Fourie, Bijan Javidi, Jim Lamb und Patricia Wagner