Um TFS-Workitems massenhaft zu bearbeiten, z.B. um mehrere Workitems einem neuem Bearbeiter zuzuweisen, gibt es verschiedene Möglichkeiten. Die bekannteste davon ist sicher die Bearbeitung in Excel. Richard Hundhausen beschreibt noch einige weitere in einem Video http://msdn.microsoft.com/en-us/vsts2008/cc563930.aspx
Jeder kenn die Situation. Wenn man einen Fehler oder eine Änderung beschreiben will, tipp man sich einen Wolf. Viel schneller geht es mit einem Screenshot. Wer allerdings, z.B. beim Testen zig Screenshots an Workitems im Team Foundation Server anhängen möchte, der ist auch schnell genervt. Immer der gleiche Prozess. Schreenshot aufnehmen - In das Bildverarbeitungsprogramm wechseln - Screenshot einfügen - Screenshot speichern - Neues Workitem anlegen udn Felder ausfüllen - Attach File aufrufen - Datei mit Screenshot suchen - Fertig! Glücklich derjenige, der den artiso Workitem Manger nutzt. Da geht das Ganze viel einfacher. 1.) Das Tray Icon Symbol mit der rechten Maustaste anklicken und auswählen ob man ein neues Workitem anlegen möchte oder an das gerade geöffnete den Screenshot anhängen möchte. 2.) Geünschten Bildbereich auswählen und Screenshot aufnehmen (Klick auf den Button im Zentrum des Fensters oder Enter drücken) 3.) Schon ist das Workitem inkl. Attachment angelegt. Wer das Ganze mal testen möchte, kann sich hier eine Demo-Version des Workitem Managers herunterladen.
Die Workitems aus dem Team Foundation Server können direkt nach Excel geladen, dort bearbeitet und wieder auf den TFS gepublished werden. Das hierzu erforderliche Add-In wird bei der Installation des Team Explorers automatisch mitinstalliert und funktioniert sehr gut. Ein wenig nervig ist allerdings, wenn man zu einem Workitem weitere Informationen sehen oder eintragen möchte und die entsprechende Spalte nicht angezeigt wird. Dann muss man die Spalte erst zur Anzeige auswählen und die Liste aktualisieren. Darüber hinaus wird die Darstellung in Excel schnell unübersichtlich, wenn man viele Felder anzeigen lässt. Wäre es nicht schön, wenn man auch in Excel den gewohnten Detail-Dialog zu einem Workitem hätte? Genau diese Funktion bietet das kostenfreie Tool Ekobit TeamCompanion for Excel. Das Workitem kann editiert und gespeichert werden. Die selbe Funktion gibt es übrigens auch für MS Project. TeamCompanion for Excel TeamCompanion for Project
In der Versionsverwaltung des Team Foundation Servers spielt Branching eine wichtige Rolle. Dabei kann man ausgehend von einem bestehenden Branch eine "Kopie" erzeugen, dort Änderungen machen und diese dann in den Ursprungsbranch zurückmergen. Leider unterstützt die UI (Sorce Control Explorer im Visual Studio) nur das mergen in den Ursprungsbrachn aus dem heraus dieser Branch abgezweigt wurde. Merging in andere Branches bezeichnet man als "Baseless Merges". Wie das geht beschreibt der TFS-Guide in einem HowTo. patterns & practices: Team Development with Visual Studio Team Foundation Server - Home
Ein Dokument auf das ich immer verweise, wenn es um die Installation des Team Foundation Servers geht ist der TFS2008 Installation Guide. Deshalb hier mal der Link für alle, die einen TFS aufsetzen wollen. Leider funktioniert das mit CD rein und Setup aufrufen nicht. Aber wenn man die Installationsanweisung befolgt, geht's meisten problemlos. Ansonsten einfach mich anmailen, ich versuche dann gerne weiterzuhelfen. Download details: Team Foundation Installation Guide
In einem Projekt nutze ich Contains um eine Liste mit IDs zu übergeben, um dann Objekte per LINQtoSQL aus der Datenbank zu lesen. Das klappt wunderbar, solange die Liste mit den IDs nicht zu groß wird. Bei knapp über 1000 IDs hatte ich allerdings ca. 5 Sek. für die Ausführung was mir dann doch recht lange vorkam. Ich habe mir dann mal mit dem SQL Profiler angeschaut, was LINQ da eigentlich treibt und hatte dann schnell eine Vermutung. LINQtoSQL ruft an der stellen nämlich eine Stored Procedure auf und übergibt die IDs als Parameter dort hin, d.h. über 1000 Parameter deklarieren und zuweisen, das könnte dauern. Ich habe das Statement dann testhalber einfach umgebaut, dass ich im SELECT direkt die IDs über ein IN(...) angab und siehe da, diese Abfrage war nun um Dimensionen schneller. Merke: Über Contains keine große Anzahl von Parametern übergeben, statt dessen lieber die Abfrage selber mit einem IN aufbauen.
Zum Aufzeichnen von WebTests mit VSTS wird ein Web Test Recorder Toolbar im IE integriert. Unter meinem Vista 64 Bit hatte ich allerdings das Problem, dass der Toolbar dort partou nicht angezeigt wurde. Nach einigem Suchen habe ich dann die Lösung gefunden: VSTS 2008 : Vista (64 bit) : Recorder bar does not appear when recording a new webtest Fix: Vista caches the list of explorer bars you have available and the recorder bar was not included in your list. The fix is to force Windows to rebuild that cache. To do this, first make sure you have all Internet Explorer instances shut down, then open the 32 bit registry editor and delete the following keys: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\Component Categories\{00021493-0000-0000-C000-000000000046} HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\Component Categories\{00021494-0000-0000-C000-000000000046} [Note: by default, the 32 bit registry editor is located in %WINDIR%\SysWow64\RegEdt32.exe] The next time you boot Internet Explorer, your explorer bar cache will be rebuilt and the recorder bar should be available. Nachdem ich diese beiden Registry-Keys gelöscht habe, wurde der Toolbar angezeigt. Weitere Infos und tipps bei Probleme mit dem Web Recoder Toolbar finden sich unter Michael Taute's Blog : Diagnosing and fixing Web Test recorder bar issues.
Es gibt eine ganz Reihe von Whitepapers, die verschiedene Practices aus dem Bereich ALM und deren Umsetzung mit VSTS beschreiben. - Communicate and Collaborate
- Drive Predictability
- Ensure Quality Early and Often
- Integrate Work Frequently
- Making Real-Time Decisions
- Managing Team Workflow
- Using Familiar Tools
Visual Studio Team System 2008 Capabilities White Papers
Durch unseren gestrigen Vortrag zu Rosario bin ich auf einen Punkt aufmerksam geworden, der mir zum Thema UI Automation so noch gar nicht bewusst war. Man kann mit UI-Automation auch Web-Anwendungen steuern. Das ist eine echt coole Geschichte. Am einfachsten verwendet man den UI-Spy um sich mal anzusehen, was da geht. Also IE auf und mal reinschauen. UI-Spy mit "Run as Administrator" starten, damit wir die Pattern anwenden können. Dann zunächst mal den Hovering mode aktivieren: Nun kann man auf der Web-Seite mit der Maus auf einen Link fahren und die CTRL-Taste drücken. Es dauert einen kurzen Moment, dann wir der Link mit einem roten Kästchen umrahmt und UI Spy zeigt das entsprechende Objekt im Baum an. Es empfiehlt sich nun, den Hovering mode wieder abzuschalten, da sonst jedes weiteres Drücken der CTRL-Taste den Scope ändern würde. Nun können wir uns die verfügbaren Patterns für das Element anschauen. Dazu einfach mit der rechten Maustaste auf den Hyperlink und dann "Control Patterns auswählen". Uns interessiert beim Hyperlink das Invoke-Pattern das Aktionen wie Click etc. ausführt. Wenn man nun auf "Call Method" klicht, wird der Hyperlink aufgerufen, d.h. der IE verhält sich, wie wenn man den Hyperlink mit der Maus anklicken würde, d.h. er ruft die entsprechende Seite auf. Nun wollen wir uns noch ansehen, wie man auch Inhalte in Textboxen und andere Controls einfügen kann. Hierzu habe ich ein Formular im IE geöffnet und wieder mit dem UISpy das Element identifiziert. Nun kann man das ValuePlattern verwenden um den Value der Textbox zu editieren. Mit diesem Wissen und dem Basiswissen aus meinem Webcast zur Erstellung von Unit-Test mit dem UI Automation Framework können wir nun Unit-Tests schreiben, die Web-Oberflächen automatisiert testen. Bleibt die Frage wo ist der Unterschied zu den Web-Tests die mit VSTS Edition for Tester erstellt werden können? Der wichtigste Unterschied ist, dass die Web-Test sog. Wired-Level-Tests durchführen. D.h. diese Tests zeichnen die HTTP-Kommunikation zwischen Client und Server auf und können diese dann abspielen und in den HTTP-Paketen bestimmte Informationen validieren. Verwendet man nun aber z.B. AJAX, dann findet dort auch eine HTTP-Kommunikation statt, z.B. beim Aufruf eines Web-Services und der Web-Service liefert auch Daten zurück, ob die im Client dann aber per Java-Script richtig verarbeitet werden bleibt fraglich. Somit testen Web-Tests den Server, nicht den Client. Mit der UI-Automation werden die Tests direkt mit den Elementen der Clients ausgeführt, d.h. ich kann z.B. auch prüfen, ob die Daten, die ein Webservice zurückliefert an der Oberfläche korrekt dargestellt werden. Der zweite Unterschied liegt einfach darin, dass das UI Automation Framework Bestandteil des .Net Frameworks 3.0 und somit kostenlos ist wohingegen für die Erstellung von Web-Tests ein VSTS for Tester notwendig ist.
Heute hatten wir bei der UG Ulm Christian Binder als Sprecher zu Gast. Christian gewährte uns einen kleinen Blick in die Zukunft der Software-Entwicklung. Er stellte einige der neuen Funktionen aus den Bereichen Project Management, Testing, Development und Architecture. Obwohl für die Demo nur das aktuelle CTP zur Verfügung stand, wurde ersichtlich, dass mit Rosario viele neue Funktionen kommen, auf die Entwickler, Tester, Architekten und Projektleiter schon lange gewartet haben. Einige der Highlights waren: - Lightweight Projektmanagement und Kapazitätsplanung
- Neue Verknüpfungen und hierarchische Workitems
- Build definition über Workflow Foundation
- Planung und Verwaltung von manuellen Tests
- Aufzeichnung eines Web UI-Tests und Umwandlung in einen coded Test
- Historical Debugging
- Sequential Diagramms
- und vieles mehr
Danke an Chris für den tollen Vortrag. 
Am 28.05.2008 findet um 18:00 Uhr das nächste Treffen der .net DeveloperGroup Ulm statt. Diesesmal haben wir Christian Binder, Microsoft Evangelist zu Gast, der uns einen Blick in die Zukunft gewährt. Er wird in seinem Vortrag Neuerungen von Rosario, dem Nachfolger von Visual Studio 2008 vorstellen. Rosario bring viele neue Funktionen, die für alle Entwickler interessant sein dürften. Wer also wissen will, was auf uns zukommt, der sollte sich diese Veranstaltung nicht entgehen lassen. Nähere Informationen gibt es unter http://www.dotnet-ulm.de/Treffen.aspx
Für eine ASP.Net Anwendung möchte ich gerne die Versionen meiner Anwendung und aller referenzierten Assemblies ausgeben. Bei Winforms kann ich für die Anwendung mit Application.ProductVersion die Version meiner Anwendung abfragen, die ich in der AssemblyInfo.cs eingestellt habe. Das geht bei ASP.Net nicht. Hier die Lösung, wie man das im Web macht, gleich mit Sortierung: Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
if (assembly != null)
{
lblProductVersion.Text = assembly.GetName().Name + " - " + assembly.GetName().Version.ToString();
var referenceAssemblies = from a in assembly.GetReferencedAssemblies()
orderby a.Name
select a;
foreach (AssemblyName referenceAssemblyName in referenceAssemblies)
{
lblProductVersion.Text += "<br>" + referenceAssemblyName.Name + " - " + referenceAssemblyName.Version;
}
}
Die Ausgabe sieht dann ungefähr so aus:
MyApplication - 1.0.3058.30144 AjaxControlToolkit - 1.0.10618.0 ArtisoAssertLib - 1.0.0.0 CommonComponents - 1.0.3056.28557 CommonContracts - 1.0.3056.28555 CrystalDecisions.CrystalReports.Engine - 11.5.3700.0 CrystalDecisions.ReportSource - 11.5.3700.0 CrystalDecisions.Shared - 11.5.3700.0 cTextBox - 1.0.3058.27781 DataContracts - 1.0.0.0 Infragistics35.WebUI.Misc.v8.1 - 8.1.20081.1000 Infragistics35.WebUI.Shared.v8.1 - 8.1.20081.1000 Infragistics35.WebUI.UltraWebChart.v8.1 - 8.1.20081.1000 Infragistics35.WebUI.UltraWebGrid.v8.1 - 8.1.20081.1000 Infragistics35.WebUI.UltraWebNavigator.v8.1 - 8.1.20081.1000 Infragistics35.WebUI.UltraWebTab.v8.1 - 8.1.20081.1000 Infragistics35.WebUI.UltraWebToolbar.v8.1 - 8.1.20081.1000 Infragistics35.WebUI.WebDataInput.v8.1 - 8.1.20081.1000 Infragistics35.WebUI.WebDateChooser.v8.1 - 8.1.20081.1000 ListValuesComponents - 1.0.3057.30147 ListValuesContracts - 1.0.3057.30146 LoginManagerComponents - 1.0.3033.29632 LoginManagerContracts - 1.0.0.0 mscorlib - 2.0.0.0 NavigationComponents - 1.0.3058.27781 NavigationContracts - 1.0.3058.27780 PCMAreaComponents - 1.0.3058.27781 PCMAreaContracts - 1.0.3058.27779 ProductsAreaComponents - 1.0.3058.27779 ProjectsAreaComponents - 1.0.3058.27780 ProjectsAreaContracts - 1.0.3058.27778 ReportingComponents - 1.0.3058.27781 ReportingContracts - 1.0.3058.27780 SearchComponents - 1.0.3058.27779 SearchContracts - 1.0.3058.27779 System - 2.0.0.0 System.Configuration - 2.0.0.0 System.Core - 3.5.0.0 System.Data - 2.0.0.0 System.Data.DataSetExtensions - 3.5.0.0 System.Data.Linq - 3.5.0.0 System.Drawing - 2.0.0.0 System.Web - 2.0.0.0 System.Web.Extensions - 3.5.0.0 System.Web.Services - 2.0.0.0 System.Xml - 2.0.0.0 TaskListComponent - 1.0.3056.28564 TaskListContract - 1.0.3056.28560 TypesComponents - 1.0.3057.30147 TypesContracts - 1.0.3057.30147 UserManagementContracts - 1.0.0.0 Validators - 1.0.0.0 wwDataBinder - 1.0.2908.21817
Für manuelle Tests muss man einen definierten Ausgangszustand schaffen um diese sinnvoll durchführen zu können. Dieser Ausgangszustand bezieht sich meist auf eine Datenbank. Um diesen Vorgang nun zu vereinfachen haben wir ein kleines Tool erstellt. Damit können Snapshots von Datenbanken erstellt und wiederhergestellt werden. Das Tool erstellt dazu einfach ein Backup der Datenbank und kann dieses Backup auch wiederherstellen. Das ist sicher nicht extrem elegant, aber sehr einfach und praktikabel. Damit das Tool funktioniert, muss man zunächst ein parr Einstellungen in der config vornehmen: 1: <?xml version="1.0" encoding="utf-8" ?> 2: <configuration> 3: <configSections> 4: <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > 5: <section name="SQLSnapshotTool.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> 6: </sectionGroup> 7: </configSections> 8: <applicationSettings> 9: <SQLSnapshotTool.Properties.Settings> 10: <setting name="Password" serializeAs="String"> 11: <value /> 12: </setting> 13: <setting name="IntegratedSecurity" serializeAs="String"> 14: <value>True</value> 15: </setting> 16: <setting name="Database" serializeAs="String"> 17: <value>Zeiterfassung</value> 18: </setting> 19: <setting name="User" serializeAs="String"> 20: <value /> 21: </setting> 22: <setting name="LocalBackupPath" serializeAs="String"> 23: <value>C:\Temp\DBSnapshots</value> 24: </setting> 25: <setting name="Server" serializeAs="String"> 26: <value>MyServer</value> 27: </setting> 28: <setting name="UNCBackupPath" serializeAs="String"> 29: <value>\\MyServer\DBSnapshots</value> 30: </setting> 31: </SQLSnapshotTool.Properties.Settings> 32: </applicationSettings> 33: </configuration>
Die wichtigsten Einstellungen hier kurz beschrieben:
Zeile 11 : Das Kennwort für den Datenbankzugriff (kann leer sein, wenn integrated Security verwendet wird) Zeile 14 : Angabe ob integrated Security verwendt werden soll. Zeile 17 : Name der Datenbank Zeile 20 : Name des Users (kann leer sein, wenn integrated Security verwendet wird) Zeile 23 : Der lokale Pfad auf dem DB-Server in den die Snapshots geschrieben werden sollen Zeile 26 : Der Name des DB-Servers Zeile 29 : Der UNC-Pfad über den auf das Sbnapshot-Verzeichnis auf dem DB-Server vom Client aus zugegriffen werden kann.
Die Bedienung ist denkbar einfach. Man gibt einfach den Namen des gewünschten Snapshots an und klickt auf "Create Snapshot". Damit wird eine Backup-Datei in das Snapshot-Verzeichnis auf dem Server geschrieben. In der Liste sieht man alle BAK-Dateien aus dem Verzeichnis und kann eine auswählen um diese dann wiederherzustellen. Das ganze ist so einfach, dass sogar Anwender damit klarkommen.
Eine Einschränkung gibt es, das Tool läuft nur mit dem SQL-Server.
Wenn jemand das Tool nützlich findet, würde ich mich über ein kurzes Feedback freuen.
Ich wollte aus Excel auf einen Webservice zugreifen. Also kurz gegoogelt (oder gelived ), eigentlich gar nicht so schwer... Aber wie so oft liegt der Teufel im Detail und es waren doch ein paar Kleinigkeiten zu beachten, deshalb hier nochmals der komplette Lösungsweg: Zunächst habe ich einen WebService erstellt, zum Testen was ganz triviales, eigentlich das Webservice Template nur noch um den Parameter Name erweitert: using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
public Service ()
{
}
[WebMethod]
public string HelloWorld(string Name) {
return "Hello World " + Name;
}
}
Die URL um auf den Webservice mit ausgefülltem Parameter zuzugreifen lautet http://localhost:49408/WebSite2/Service.asmx/HelloWorld?Name=Test, jedoch funktioniert das standardmäßig noch nicht. Wir müssen erst noch in der web.config folgenden Eintrag hinzufügen:
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
</protocols>
</webServices>
Nun bekommen wir mit diesem Aufruf den XML-Response des Webservices direkt zurückgegeben. Nun wollen wir den Webservice aus VBA aufrufen.
Sub CallWebService()
Dim MSXML As New MSXML2.DOMDocument
Dim strAnfrage As String
strAnfrage = "http://localhost:49408/WebSite2/Service.asmx/HelloWorld?Name=Test"
With MSXML
.async = False
.preserveWhiteSpace = False
.validateOnParse = True
.resolveExternals = False
End With
If MSXML.Load(strAnfrage) = True Then
Response = MSXML.DocumentElement.Text
Else
Response = "Fehler"
End If
End Sub
Damit das funktioniert müssen wir noch die Bibliothek "Microsoft XML, vx.0" einfügen. Wir werten im Moment das XML-Dokument sehr einfach aus, da wir davon ausgehen, dass der Rückgabewert einfach als Textim XML-Dokument zurückgegeben wird. Damit können wir einfach mit MSXML.DocumentElement.Text den gewünschten Wert auslesen. Natürlich können auf diese Weise auch komplexer Rückgabewerte ausgewertet werden, aber das wollen wir hier nicht näher beleuchten.
Verwendet man ein DataSet mit DateTime-Werten in unterschiedlichen Zeitzonen, wird man zu seiner Überraschung feststellen, dass das DataSet eine Umrechnung der Zeiten vornimmt. Bei uns war das Problem konkret, dass ein DataSet per WCF zu einem Service übertragen wurde. Der Service war aber in einer anderen Zeitzone als der Client. In einem DateTime-Feld wurde ein Datumswert abgelegt, also z.B. 08.05.2008. Die automtische Umrechnung hat davon jedoch eine Stunde abgezogen, so dass am Service 07.05.2008 23:00 ankam. Damit war das Datum immer um einen Tag verschoben. Das Problem kann aber behoben werden, indem man auf dem Client und auf dem Service den DateTime-Wert vor bzw. nach der Serialisierung konvertiert. Auf dem Client sieht das dann z.B. so aus: 1: foreach (DataSet1.DataTable1Row dr in ds.DataTable1.Rows) 2: { 3: dr.Date = dr.Date.ToLocalTime(); 4: }
Und dann auf dem Service das Gegenstück:
1: foreach (DataSet1.DataTable1Row dr in ds.DataTable1.Rows) 2: { 3: dr.Date = dr.Date.ToUniversalTime(); 4: }
Damit kommt genau der Wert, der im Client eingetragen wurde auch im Service an. Zwar gibt es wohl auch eine Möglichkeit, die Datumskonvertierung zu unterdrücken, aber das hat bei mir nicht sauber funktioniert. Wenn also jemand eine elegantere Lösung kenn, nur her damit 
Update:
Wir habe doch noch eine elegantere Lösung gefunden. Auf dem DataSet kann man auf der DateTime Column das Property DateTimeMode auf Unspecified umstellen. Dann wird die Zeitzonen-Konvertierung nicht durchgeführt. Danke an Luke für den Tipp.

| |