Der Team Foundation Server bietet ein extrem flexibles und leistungsfähiges Konzept zur Definition von Work Items. Damit lassen sich viele Szenarien über eine reine Konfiguration abbilden. Um die Mächtigkeit zu demonstrieren, hier ein paar Beispiele. Diese Beispiele nutzen den Process Template Editor der Bestandteil der kostenlosen Team Foundation Server 2010 Power Tools ist. 1.) Nur bestimmte Benutzer sollen ein Workitem eines bestimmten Typs anlegen dürfen Ein verbreitetes Szenario ist, dass nur ein bestimmter Personenkreis Workitems eines bestimmten Typs (in diesem Beispiel der Typ Bug) anlegen dürfen, andere Benutzer sollen diese aber weiter bearbeiten können. Auch wenn die Umsetzung nicht ganz ideal ist lässt sich diese Funktion mit dem TFS relativ einfach erreichen. Wie im Screenshot zu sehen, ist der Status Active für diesen Benutzer ungültig. Damit kann er das Workitem nicht speichern. Wie gesagt, nicht gerade schön aber wirkungsvoll. Wie erreichen wir nun diese Funktion? Im Process Template Editor sehen wir im Workflow des Bug-WIT eine Transition von nirgendwo nach Active Diese Transition wird verwendet wenn ein neues Workitem angelegt wird. Auf dieser Transition können wir nun eine Berechtigung einstellen. Dazu geben wir in das Feld “For” eine TFS Gruppe ein die diese Funktion ausführen darf. Alternativ kann bei “Not” eine Gruppe angeben die diese Transition nicht nutzen darf. Dieses Feature kann natürlich auch für Transitions zwischen zwei Status genutzt werden, also z.B. um zu steuern wer den Bug schließen darf. 2.) Ein Feld muss gefüllt sein wenn ein anderes einen bestimmten Wert hat In der Praxis kommt es häufiger vor, dass iin Abhängigkeit eines Wertes ein anderes Feld ausgefüllt sein muss. In unserem Beispiel nehmen wir mal an, dass auf dem Bug die Repro-Stepsausgefüllt sein müssen wenn der Bug die Priorität 1 hat. Dazu stellen wir auf dem Feld Repro Steps eine WHEN-Regel ein Und sagen wenn diese Bedingung erfüllt ist, dann soll das Feld ein Pflichtfeld sein 3.) Befüllen einer Auswahlliste in Abhängigkeit eines anderen Feldes Das dritte Beispiel soll uns die Auswahlliste eines Feldes in Abhängigkeit eines anderen Feldes befüllen. In unserem Beispiel soll das Feld Team in Abhängigkeit der Area befüllt werden. Dazu definieren wir für das Feld Team das wir zuvor hinzugefügt haben 2 When-Regeln An dieser Stelle verwenden wir für die Regel nicht das Feld AreaPath da hierarchische Felder in Regeln nicht richtig unterstützt werden. Diese produzieren dann beim Import des WIT den Fehler "TF26204: The account you entered is not recognized". Der Umweg über die AreaID umgeht diese Problem. Dann stellen wir einfach die AllowedValues für die beiden Fälle ein. Man sieht also, dass der TFS einiges an Flexibiölität zu beieten hat. Es lohnt sich damit mal etwas zu experimentieren. Generell möchte ich aber vor Überregulierung warnen weil dies in der Praxis meist dazu führt, dass die Anwender behindert werden und somit die Akzeptanz des Tools sinkt.
Tritt beim Konfigurieren eines Labs das in einer Workgroup betrieben wird (keine Domänenintegration der VMs) folgender Fehler auf, dann fehlt ggf. ein Shadow-Account:
-------------------------------------------------- Environment message: Type=Warning; Message=TF267042: One or more machines are not ready to run tests. For more information, see the individual machine errors.; Machine messages: Machine name: Windows 7 x64 en Machine message: Type=Error; Message=TF267055: The machine is not ready to run tests because of the following error: Unable to connect to the controller on ---. The agent can connect to the controller but the controller cannot connect to the agent because of following reason: The server has rejected the client credentials. The logon attempt failed.; -------------------------------------------------- Damit der Testagent mit dem Testcontroller korrekt zusammenarbeitet, müssen beide mit unterschiedlichen Accounts laufen. Der Testcontroller verwendet dabei typischerweise einen Domänen-Account, der Testagent arbeitet mit einem lokalen Account. Die jeweiligen Accounts müssen als Shadow-Accounts (gleicher Name und Kennwort) lokal bzw. in der Domäne angelegt werden, also für den lokalen Account ein Shadow-Account in der Domäne und für den Domänen-Account ein lokaler Shadow-Account. Beispiel: | | Account | Shadow-Account | | Testagent | labmachine\Labuser | domain\Labuser | | TestController | domain\TestController | labmachine\TestController | Die oben beschriebene Meldung erhält man, wenn auf der Labmaschine kein lokaler Shadow-Account angelegt wurde. Wenn man das nachholt und dann auf “Repaiur testing capabilities” klickt, dann sollte das Problem behoben sein. 
Im Team Foundation Server lassen sich die Work Items sehr einfach anpassen, neue Work Item Types lassen sich erzeugen und damit ein individuelles Process Template erzeugen. Das ganze geht sehr einfach und intuitive wenn mann den Process Template Editor aus den Team Foundation Server Power Tools verwendet (http://visualstudiogallery.msdn.microsoft.com/en-us/3e8c9b68-6e39-4577-b9b7-78489b5cb1da) Wer mal auf den Geschmack gekommen ist, das Process Template im TFS anzupassen, wird durch ausprobieren und rumspielen schnell vor der Frage stehen, wie kann ich nun in einem bestehenden Projekt einen Work Item Type wieder löschen den ich nicht mehr brauche? Hier hilft das Kommandozeilentool witadmin weiter das sich dirckt über die Visual Studio Eingabeaufforderung ausführen lässt. witadmin destroywitd /collection:http://<Servername>:8080/tfs/<Team Project Collection> /p:<Team Projekt Name> /n:<Name des Work Item Types> löscht den angegebenen Work Item Type. Vorsicht, mit diesem Kommando werden aber auch alle Work Items gelöscht, die diesen Typ verwenden, diese können ja vom System nach löschen der WITD nicht mehr verwaltet werden. Wenn man also den WIT bestehender Work Items verändern möchte, dann sollte man diesen umbenennen und anschließend so anpassen dass er den neuen Anforderungen entspricht. Zum Umbenennen eines WIT hilft ebenfalls witadmin witadmin renamewitd /collection:http://<Servername>:8080/tfs/<Team Project Collection> /p:<Team Projekt Name> /n:<Alter Name des Work Item Types> /new:<Neuer Name des Work Item Types>
Bei der weltweiten Usergroup Team System User Group Virtual Edition hat sich in den letzten Tagen einiges geändert, z.B. der Name. Wie das Produkt das im Zentrum unserer Aktivitäten steht, wurde die Gruppe in Visual Stuido ALM User Group umbenannt. Gleichzeitig haben wir eine neue Website online geschaltet. Sie finden uns jetzt unter http://www.vsalmug.com/default.aspx In diesem Zuge werden wir zukünftig die Benachrichtigungen für unsere Meetings nicht mehr per E-Mail zustellen, sondern sie können sich Neuigkeiten unseren Blog mit den Ankündigungen per RSS abrufen (http://www.vsalmug.com/CMSPages/BlogRss.aspx?aliaspath=/Meetings/Announcements). Zusätzlich ahben wir auf LinkedIn eine Gruppe eingerichtet über die sich die Mitglieder besser untereinander vernetzen können: http://www.linkedin.com/groups?home=&gid=2860483&trk=anet_ug_hm Abschließend möchte ich auf unseren nächsten Vortrag noch hinweisen. Am Donnerstag, 06.05.2010 ab 19:00 wird Martin Woodward vorstellen wie die Integration mit nicht Microsoft-Plattformen über den Team Explorer Everywhere (vormals Teamprise) gelingt.  Team Explorer Everywhere 2010 Meeting Date: Thursday, May 6th, 2010 Time: 10:00AM PT (UTC-0700) [Add to Calendar] [Join Meeting] Did you know that Team Foundation Server can be used for software development by your entire organization - not just the team using Microsoft platforms and technologies? In this session Martin Woodward will show you how you can get your Java, Mac, Linux, and Eclipse developers on board using Team Explorer Everywhere 2010. This session shows you how you can standardize on Team Foundation Server for the Application Lifecycle Management of your entire enterprise. See how to manage work items, version control, and build automation across technology and platform boundaries in your company and understand the features and functionality available to the people in your organization. Speaker: Martin Woodward Martin Woodward is the Program Manager for the Microsoft Visual Studio Team Foundation Server Cross-Platform Tools Team and co-author of the book "Professional Application Lifecycle Management with Visual Studio 2010". Before joining Microsoft, Martin was voted Team System MVP of the Year and has spoken about Team Foundation Server at events internationally. Not only does Martin bring a unique insight into the inner workings of the product he has experience from over a half-decade of real world use at companies big and small that he is always happy to share. When not working or speaking, Martin can be found at his blog http://www.woodwardweb.com.
So langsam reift bei den letzten Source Safe Moikanern die Erkenntniss, dass es nun langsam Zeit wird sich nach einer anderen Quellcodeverwaltung umzusehen und eigentlich liegt da inzwischen nichts näher als der Team Foundation Server 2010 der nicht nur eine erstklassige Versionsverwaltung mit bringt sondern der acuh eine Vielzahl weiterer ALM-Funktionen beinhaltet und vor allem inzwischen in der MSDN Subscription kostenloas enthalten ist. Wer wissen will, wie er schnell und einfach von Source Safe auf TFS migriert, findet alle notwendigen Infos hier : http://msdn.microsoft.com/en-us/library/ms253060.aspx
In der TFS Adminconsole oder im TFS Configuration Wizard können die Reporting Services für den TFS konfiguriert werden.  Man gibt hier den Server und ggf. die Instanz der Reporting Services an und klickt auf “Populate URLs”, dann werden die entsprechenden URLs automatisch ausgefüllt – normalerweise zumindest. Ich hatte die Situation, dass der User mit dem ich den TFS installiert habe auf dem Server auf dem die Reporting Services liefen kein Administrator war. Normalerweise ist das der einfachste Weg, den TFS Account auf dem Reporting Server als lokalen Administrator einzutragen, das ist aber nicht in allen Fällen erwünscht. Dann bekommt man die Fehlermeldung TF255050: A connection cannot be made to the Report Server WMI provider. Verify the following: 1. You have entered the correct name for the server, including the instance name. 2. The Windows Management Instrumentation service is running on vs2010rcdemo. 3. The service is not blocked by Windows Firewall. 4. You have the required permissions to connect. Details: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) Eine damit verwandte Fehlermeldung ist TF255186: The following SQL Server Reporting Services Instance could not be found: MSSQLSERVER. The server name is: vs2010rcdemo. In beiden Fälle fehlen dem User WMI-Berechtigungen auf dem Reporting Server. Im ersten Fall der Remote-Zugriff auf die WMI generell, im zweiten Fall auf den Remote-Zugriff für die Reporting Services in der WMI. Um die gewünschte Operation ausführen zu können muss dem User zunächst Remote-Zugriff auf WMI gegeben werden: - Auf dem Reporting Server dcomcnfg.exe starten
- Im linken Bereich Console Root\Component Services\Computers\My Computer öffnen
- Aus dem Kontextmenü von “My Computer” den Eintrag “Properties” öffnen
- Im Bereich “Launch and Activation Permissions” auf “Edit Limits” klicken
- Den Benutzer mit “Add hinzufügen und ihm “Remote Launch” und “Remote Activation” vergeben
Anschließend kann der Remote-Zugriff per WMI auf die Reporting Services konfiguriert werden. - Auf dem Reporting Server wmimgmt.msc starten
- Im linken Bereich auf WMI Control (Local) aus dem Kontext-Menü “Properties” auswählen
- Auf den Reiter Security wechseln und im Baum Root\Microsoft\SqlServer\ReportServer auswählen
- Auf den Button “Security” klicken und den gewünschten benutzer mit “Add” einfügen
- Dem Benutzer “Enable Account” und “Remote Enable” als Rechte vergeben
- Auf “Advanced” clicken, den Benutzer auswählen und dann auf “Edit” klicken
- Bei “Apply to” “This namespace and subnamespaces” wählen
Mit diesen Einstellungen sollte nun das “Populate URLs” in der TFS Administration Console funktionieren.
Wer sich eine Trial-Version von Visual Studio 2010 oder Team Foundation Server 2010 installiert benötigt einen Key um diese freizuschalten. Wer nun über eine MSDN-Subscription verfügt, kann sich die Vollversion dort herunterladen, jedoch man bekommt keinen Key. Nun kann man entweder neu installieren oder man greift zu einem kleinen Trick: - ISO-File vom MSDN herunterladen
- Im ISO-Image nach der Datei setup.sdb suchen
- Die Datei mit einem Texteditor öffnen
- Der Key steht unter dem Eintrag [Product Key] und kann von hier einfach in das Registrierungsformular übertragen werden. Dazu im TFS einfach die Admin-Console öffnen und im Visual Studio unter Help / Register Product aufrufen
Update: Inzwischen hatte MS ein Einsehen und die Keys bei den MSDN Subscriber Downloads veröffentlicht 
Beim Deployment einer Environment auf meinen Host bekam ich den Fehler TF259115:  Speicher war eigentlich genug frei auf meinem Host und so war ich zunächst erstaunt, warum er das nicht deployen wollte. Des Rätsels Lösung liegt darin, dass die Placement Policy standardmäßig auf “Conservative” eingestellt ist. Das bedeutet, dass der Host beim Deployment den Speicherbedarf aller VMs auf dem Host ermittelt, unabhängig davon ob diese gestartet sind oder nicht. Im Betrieb könnten ja dann alle gleichzeitig gestartet werden was dann zu Problemen führt. D.h. im Idealfall hat man immer soviel Ressourcen, dass alle Environments die deployed sind gleichzeitig laufen können, momentan nicht benötigte Environments werden in der Library abgelegt. Da ich aber auf meinem Demo-Notebook nicht soviel Speicher habe und dabei nie alle Environments gleichzeitig laufen sollen, wollte ich diese Limitierung umgehen. Dies kann man erreichen, indem man die Placement Policy auf Aggresive stellt. Dies erreicht man am besten durch einen TFSConfig-Aufruf: TfsConfig Lab /hostgroup /CollectionName:labcollection /Edit /Name:"All Hosts" /LabEnvironmentPlacementPolicy:Aggressive Logging sent to file C:\ProgramData\Microsoft\Team Foundation\Server Configuration\Logs\CFG_SET_URL_0413_225508.log Command: lab TfsConfig - Team Foundation Server Configuration Tool Copyright (c) Microsoft Corporation. All rights reserved. Are you sure you want to update the settings for this host group ? (Yes/No) y The requested changes were successfully applied. Die TFSConfig findet befindet sich im Pfad C:\Program Files\Microsoft Team Foundation Server 2010\Tools Weitere Infos unter http://msdn.microsoft.com/en-us/library/dd547199(VS.100).aspx
Heute wurden Visual Studio 2010 und Team Foundation Server 2010 gelauncht. Microsoft neueste ALM Plattform bietet eine große Anzahl neuer Features, so dass sich ein näherer Blick auf jeden Fall lohnt, unter anderem: - Testmanagement und Testausführung
- automatisierte GUI-Tests
- Virtualisierte Testumgebungen
- Erweiterte Tracking-Funktionen für Versionsverwaltung
- Agile Planungsmethoden
- Build Workflows auf Basis von WF 4.0
- Architektur-Features und UML-Diagramme
- Integrierte SharePoint-Entwicklung
- uvm
Ich werde in den folgenden Wochen in einzelnen Blogbeiträgen verschiedene Funktionen vorstellen, also vorbeischauen lohnt sich … Weitere Informationen und den Download Link für Inhaber einer MSDN Subscription finden sich hier: http://msdn.microsoft.com/de-de/vstudio/2010.aspx Testversionen können hier heruntergeladen werden: http://www.microsoft.com/germany/visualstudio/try/download.aspx
Team Foundation Server 2010 bietet nun eine verbesserte Integration mit SharePoint. Für die einzelnen Team-Projekte wird die Verbindung zu einer SharePoint Site typischerweise beim Anlegen des Projektes einrichten, alternativ kann man das auch im Nachhinein konfigurieren. Dazu einfach im TeamExplorer auf dem Team Projekt rechte Maustaste und dann unter “Team Project Setting” “Portal Settings” auswählen. Hier wählt man dann unter “Configure URL” eine der konfigurierten Web Applications aus. Bekommt mann beim Bestätigen des Fensters folgen Meldung, dann hat der aktuelle Benutzer nicht ausreichen Berechtigungen auf die Site / SiteCollection: Server was unable to process request. ---> Failed to activate feature 'TeamFoundationWeb' (ID: 310284e3-35d9-4b5d-99b5-c42147379877) at scope 'http://sarmoss02/sites/TFS2008/BI_KaBIS'. Diese Berechtigungen müssen im SharePoint eingetragen werden.
Will man in einer Winforms-Anwendung einen String URL-encodieren, dann kann mann dafür einen einfachen Aufruf verwenden: HttpUtility.UrlEncode("http://www.artiso.com/page?ID=99"); Das einzige wass man dafür tun muss, ist die System.Web.dll zu referenzieren. Eine kleine Hürde gibt es bei Visual Studio 2010, da hier standardmäßig “.Net Framework 4 Client Profile” als Target-Framework ausgewählt ist und das Client Profile die System.Web nicht enthält. Deshalb muss man in den Eigenschaften des Projektes das Target-Framework umstellen, z.B. auf .NET Framework 4. 
Wollte heute ganz einfach eine Benachrichtigung für eine Liste im SharePoint einrichten. Das Ganze stellte sich als problematischer heraus als gedacht. Eigentlich ist das eine einfache Sache. Im Actions-Menü die Option “Aletr Me” aufrufen… … , Einstellungen vornehmen und schon kommt eine Fehlermeldung: The following users do not have e-mail addresses specified: <UserName>. Alerts have been created successfully but these users will not receive e-mail notifications until valid e-mail addresses have been provided Der Link darunter mit “Set my e-Mail address” war auch nicht sehr hilfreich. Nach einigen Recherchen bin ich dann auf ein paar weitere Details gestoßen. Zunächst habe ich herausgefunden, dass SharePoint die Benutzerprofile mit dem ActiveDirectory abgleicht, aber nur, wenn das konfiguriert ist. Das kann man unter Central Administration \ Shared Services Administration einstellen. Dort kann man im Dropdown-Menü des SharedService die Option “Open Shared Services Admin Site” aufrufen. Unter “User Profiles and My Sites” kann nun die Option “User profiles and properties” gewählt werden. Hier sollte zunächst geprüft werden, ob der Dienst der die User Profile mit dem ActiveDirectory abgleicht auch zur Ausführung eingeplant ist. Mit den unteren Links kann ein manueller Abgleich gestartet werden. Über “View user profiles” kann man sich die importierten Profile anzeigen lassen, mit “View import log” kann man sich ein Protokoll zum Abgleich anzeigen lassen. Sollen die Benutzer aus einer anderen Domäne importiert werden als die in der der SharePoint Server läuft, kann man über “View Import Connections” eine weitere Domäne hinzufügen. Bei mir bestand dann noch das Problem, dass das Profil für meinen User nicht sauber durch den Import aktualisiert wurde. Nachdem ich den User aus der entsprechenden Site entfernt und neu hinzugefügt hatte, hat es problemlos funktioniert und ich kann jetzt meine Alerts problemlos einrichten und bin immer auf dem Laufenden was den Inhalt meiner SharePoint-Listen anbelangt.
Mit TFS 2010 kommen nun endlich hierarchische Workitem Queries und erfreulicherweise lassen diese sich auch im SharePoint Portal schön darstellen. Was mich an der Geschichte nur etwas gestört hat, dass ist, dass die Hierarchie nach dem Laden immer vollständig aufgeklappt ist. Es gibt zwar einen Button “Collapse All” aber den dann immer extra zu drücken um erst mal einen Überblick zu bekommen, ist doch etwas lästig. Zunächst habe ich deshalb versucht die Query entsprechend anzupassen, jedoch gibt es an dieser Stelle leider noch keinen Parameter um das einzustellen. Für das SharePoint-Portal habe ich allerdings eine Lösung gefunden und die geht so: 1.) Ein neues Content Web Part auf der Seite einfügen: 2.) Auf dem Content Editor Web Part den Source Editor starten 3.) Hier folgendes Script eintragen: 1: <script language="javascript"> 2: function collapseQuery() 3: { 4: _ctl00_m_g_1409303e_8eb2_4dc3_80b0_822628dfcc28_ctl00.tryToggle(false, true); 5: } 6: 7: WPSC.RegisterForEvent("urn:schemas-microsoft-com:dhtml","onload",collapseQuery); 8: </script>
Die ID des Webparts (_ctl00_m_g_1409303e_8eb2_4dc3_80b0_822628dfcc28_ctl00) lässt sich relativ einfach im HTML-Source der Seite ermitteln (z.B. IE 8 F12 drücken um in die Developer Tools zu gelangen). Hier kann man dann über Find / Select Element by Click durch Anklicken des WebParts die Stelle im Code einfach finden und die ID zu ermitteln. Zu beachten ist dabei, dass das die ID des Controls etwas anders lautet als das WebPart selbts, so muss am Anfang ein _ stehen und das Control auf _ctl00 enden.

Mit dem TFS 2010 ist es nun möglich, denn Application-Tier über einen NLB-Cluster zu betreiben. Damit kann man Ausfallsicherheit und Load-Balancing für den App-Tier erreichen. Mit einem SQL-Cluster als Data-Tier skaliert der TFS nun sehr schön, sowohl in Punkte Performance als auch in Bezug auf die Ausfallsicherheit. Nun liegt es natürlich nahe, die Reporting Services ebenfalls über den NLB zu betreiben, was an sich auch kein Problem ist. Man muss nur ein paar Einstellungen vornehmen. So hats bei mir funktioniert: 1.) Das Scale-out Deployment für die Reporting-Services auf beiden Servern aktivieren (setzt SSRS Enterprise voraus) 2.) Die Web Service URL auf die IP-Adresse des NLB einstellen 3.) In der TFS Admin Console die Reporting Services über den NLB registrieren. Das hat bei mir nur über die IP-Adresse funktioniert, nicht über den Namen. Da muss ich bei Gelegenheit mal danach schauen. 4.) In der Datei C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services\ReportServer\rsreportserver.config unter <Service> folgendes Tag einfügen: <Hostname>sartfsnlb01</Hostname> 5.) In der Web.config unter C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services\ReportServer\ und unter C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services\ReportManager\ im Abschnitt <system.web> folgenden Tag einfügen: <machineKey validationKey="627BF72BB33AA8D28CA2C3E80920BA4DF0B726F97EEFBB0F4818350D63E6AFA380811F13ED1F086E386284654DB3DAF676707464EEB73EBF79858F477D8E4F5C" decryptionKey="F40B6E5A02B29A181D2D213B5ED8F50B73CFCFD0CC56E137" validation="SHA1" /> Achtung die Parameterwerte dürfen nuicht umgebrochen werden. Einen eigenen Key kann man sich einfach unter http://aspnetresources.com/tools/keycreator.aspx generieren lassen. 6.) Reporting Srevices neu starten. 7.) Nun werden bei einem Ausfall eines App-Tiers alle Reporting-Anfragen über den anderen App-Tier abgewickelt, der Anwender merkt davon nichts außer dass es beim ersten Zugriff nach dem Ausfall ein wenig länger dauert.
Dieses Jahr ist nach längerer Zeit die TechEd, die wichtigste Microsoft-Konferenz in Europa, wieder in Deutschland, genauer gesagt vom 09.Nov – 13. Nov in Berlin. Ich werde dort als ATE (Ask the Experts) zum Thema Visual Studio ALM vertreten sien und darüber hinaus mit Christian Binder und Neno Loje ein Q&A Session zu den Themen TFS, ALM und Visual Studio 2010 zu machen. Die Session wird in Deutsch sein, also wenn ihr Fragen rund um den Themenbereich habt, besucht unsere Q&A-Session. Soviel geballtes Wissen auf einmal gibts nicht so bald wieder  Visual Studio Team Foundation Server Q&A Mittwoch, 11. November 14:00 – 15:00 Uhr Community Stage im Zentrum der Ausstellung Halle 4.2 
Hype-V ist ein klasse Virtualisierungssystem das vor allem in der neuesten Version eine Reihe nützlicher Funktionen mitbringt. Besonders hilfreich sind Snapshots mit denen es gefahrlos möglich ist, auch auf dem Server mal was zu testen. Man kann sich aber mit Shanpshots leicht selber überlicsten oder gar in’s Knie schießen. Deshalb möchte ich hier ein paar Erfahrungen zum Besten geben: Funktionsweise von Snapshots Die Virtuellen Maschinen von Hyper-V schreiben ihre Daten in virtuelle Harddisks (VHD), also eine Datei auf der Platte des Hosts. Wird nun ein Snapshot gemacht, passiert vereinfach gesagt, Folgendes. Die VHD-Datei wird schreibgeschützt, so dass daran keine Änderungen mehr vorgenommen werden können. Statt dessen wird nun eine AVHD-Datei angelegt und alle Änderungen auf der Platte der VM werden nun dort hineingeschrieben. Wird erneut ein Snapshot erstellt, wird die AVHD gesperrt und eine weitere angelegt. Dies hat nun zweierlei Folgen: - Je mehr Snapshots erstellt werden, desto langsamer wird der Zugriff auf die virtuelle Disk, da Hyper-V ja aus der VHD und den verschiedenen AVHDs nun die Daten zusammensammeln muss.
- Nur die VHD und alle AVHDs zusammen ergeben den aktuellen Stand der virtuellen Disk, mit der VHD alleine hat man nur den Stand vom ersten Snapshot.
Gerade der letzte Punkt ist beim Verschienen der VM oder beim Backup zu berücksichtigen, da man hier schnell Daten verlieren kann, wenn man vergisst die AVHDs zu berücksichtigen. Aus beiden oben genannten Gründen macht es Sinn, Snapshots zu löschen, sobald diese nicht mehr gebraucht werden. Snapshots sind keine Technik zur Erstellung von Backups! Zum löschen eines Snapshots wird dieser einfach selektiert und dann mit “Delete” gelöscht. Aber ACHTUNG! Die Daten liegen nun immer noch in der AVHD. Erst wenn man die VM in den Save-State fährt, beginnt Hyper-V mit einem Merge, d.h. die Änderungen der AVHDs werden jetzt in die jeweils vorausgegangene AVHD bzw. VHD gemerged, sind alle Snapshots gelöscht, bleibt nur noch die VHD übrig. Erst nach Abschluss des Merge-Vorgangs erhält man durch eine Kopie der VHD eine komplette Sicherung der virtuellen Disk der VM.
Die .net Developer Group Ulm bietet am 27.10.2009 eine kostenlose Ganztagesveranstaltung rund um Visual Studio 2010 ALM (vormals VSTS 2010). Die Nachfrage für diese Veranstaltung ist so hoch, dass wir uns entschieden haben, die Veranstaltung am 26. November nochmals mit gleichen Sprechern und gleichem Inhalt zu wiederholen. Wer also noch Interesse hat, sollte sich bald möglichst unter http://www.dotnet-ulm.de/vsts2010/ registrieren, wir haben noch ein paar Plätze frei.
 Die Beta 2 von Visual Studio 2010 ist nun für MSDN Subscribers verfügbar, für alle anderen wird es noch bis Mittwoch dauern. Es gibt eine reihe von wichtigen Änderungen die Microsoft mit Visual Studio 2010 ankündigt: - Es gibt eine abgespeckte Version von TFS (TFS Basic) die auch auf Client-Betriebssystemen installiert werden kann.
- TFS ist jetzt in alle versionen von Visual Studio 2010 enthalten (meines Wissen nach nur bei denen mit MSDN)
- Es gibt ein vereinfachtes Modell der Produkt SKUs (Editionen)
- Neues Logo (siehe oben)
Was ich persönlich schade finde: Die Bezeichnung “Team System” verschwindet, es gibt nun nur noch - Microsoft® Visual Studio® 2010 Express
- Microsoft® Visual Studio® 2010 Professional
- Microsoft® Visual Studio® 2010 Professional with MSDN
- Microsoft® Visual Studio® 2010 Premium with MSDN
- Microsoft® Visual Studio® 2010 Ultimate with MSDN
- Microsoft® Visual Studio® Test Elements 2010 with MSDN
- Microsoft® Visual Studio® Team Foundation Server 2010
- Microsoft® Visual Studio® Team Lab Management 2010
- Microsoft® Visual Studio® Load Test Virtual User Pack 2010
Positiv ist aber, dass die Beta 2 eine Go-Live-Lizenz enthält. Der Launch-Termin wirde von Microsoft für den 22. März 2010 angekündigt. http://blogs.msdn.com/somasegar/archive/2009/10/19/announcing-visual-studio-2010-and-net-fx-4-beta-2.aspx
In Expression Blend gibt es ein cooles Feature, mit dem Beispieldaten für Databinding erzeugt werden können. Damit können beispielsweise Listboxen etc. mit Daten befüllt werden um z.B. DataTemplates im Designer testen zu können. Und auch bei der Ausführung der Anwendung stehen die Daten zur Verfügung. Damit können schnell und einfach Oberflächenprototypen erstellt werden. Eine detaillierte Beschreibung der Funktion findet sich hier.
Auf der diesjährigen ADC hatte ich zwei Vorträge: Zu beiden Vorträgen gibt es die Unterlagen über den jeweiligen obenstehenden Link.
Hat man eine Query die zwei Spalten mit dem gleichen Namen enthält, dann mekert der Reporting Services Designer “The query contains more than one unnamed or duplicated field name. Please specify unique column aliases.” In der MDX-Abfrage Aliase zu vergeben ist mir nicht gelungen. Glücklicherweise gibt es aber einen einfacheren Weg das Problem zu lösen. Man geht einfach in die Eigenschaften des Datasets und dort auf “Fields”. Hier kann man nun einfach einen eindeutigen Alias angeben. 
Oft möchte man Werte, z.B. Prozentwerte als kleine Balken in einem Report darstellen: Wie man das mit Hilfe der Reporting Services bewerkstelligt, ist im Folgenden kurz beschrieben. - Zunächst erstellt man sich eine Grafik mit dem gewünschten Verlauf
- Dann fügt man eine neue Spalte mit dieser Grafik in den Report ein. Der Grafik gibt man ein günstige Breite, z.B. 100px.
- Für die Grafik stellt man nun ein Padding für den rechten Rand ein und zwar über eine Expression:
- In der Expression gibt man nun eine Formel ein, die den rechten Rand so berechnet, dass er bei 0 die Breite des Bildes erreicht und beim Maximalwert 0.
- In obigem Beispiel hat das Bild eine Breite von 100pt und soll einen Maximalwert von 1.5 anzeigen, so dass bei 1.5 der Wert für das Padding 0 ist und bei 0 ist er 100 (1,5 * 75). Damit zeigt der Balken die Werte grafisch an. Auf Wunsch kann man natürlich den Wertebereich auch min Min() und Max() ermitteln.
http://blogs.msdn.com/bobmeyers/archive/2005/10/15/481342.aspx
Meinem SQL-Server kam bei einer meiner Datenbank-Tabellen was supekt vor jedenfalls zeigte er in Klammern hinter der Tabelle ein (Suspect) an und ich konnte auf die Tabelle nicht mehr zugreifen. Ärgerlich war, dass es sich dabei um die Config-Datenbenk meines SharePoint-Servers handelte und damit mein kompletter SharePoint-Srever lahm gelegt war. Glücklicherweise fand ich ein kleines Script, das das Problem in Sekunden behoben hat. EXEC sp_resetstatus 'DBname'
ALTER DATABASE DBname SET EMERGENCY
DBCC checkdb('DBname')
ALTER DATABASE DBname SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DBCC CheckDB ('DBname', REPAIR_ALLOW_DATA_LOSS)
ALTER DATABASE DBname SET MULTI_USER
Dort habe ich einfach meinen Datenbanknamen entsprechend eingesetzt und schon lief der SharePoint wieder. Vielen Dank an der Stelle an Mohamad. http://mshehadeh.blogspot.com/2007/09/restoring-sql-server-2005-suspect.html
Mit Team Foundation Server 2010 wird der TFS nun auch für kleinere Teams noch interessanter als bisher. Es gibt eine Reihe von Vorteilen gegenüber der aktuellen Version: - Preis
Es gibt im Moment noch keine abschließenden Informationen über das Pricing, aber voraussichtlich wird der Preis zukünftig wohl kaum noch ein Argument sien, den TFS nicht zu nutzen. - Systemanforderungen
Die Anforderungen an das System sind deutlich geringer als bei TFS 2008. So kann der TFS nun auf einem Domänen-Controller und sogar auf Client-Betriebssystemen installiert werden. Zudem können nun einige Komponenten wie SharePoint und Reporting optional installiert werden. - Installation
Der Installationsvorgang wurde deutlich vereinfacht. Damit kommt Microsoft dem Slogen “ALM for the masses” einen großen Schritt näher. Weitere Details gibt es auf dem Blog von Brian Harry: http://blogs.msdn.com/bharry/archive/2009/10/01/tfs-2010-for-sourcesafe-users.aspx
Mit dem Work Item Type Designer (WIT Designer) können Work Item Type Definitionen einfach und bequem angepasst werden. Der WIT Designer ist Bestandteil der TFS Power Tools. Mit dem WIT Designer kann man auch die Workflows auf den Work Item Types grafisch bearbeiten. Dazu kann man aus der Toolbox einfach neue States und Transistions auf das Workflow-Diagramm ziehen … zumindest wenn die Toolbox Elemente enthält. Sollte die Toolbox einmal leer sein, dann gibt es eine nicht ganz elegante aber wirksame Methode, man löscht einfach alle toolbox*.tdb Dateien und zwar au dem Ordner C:\Users\<USERNAME>\AppData\Local\Microsoft\VisualStudio\8.0. Danach erscheinen die Elemente ganz normal.
Wir haben einen neuen Nachbarn bekommen In Augsburg gibt es nun auch eine .net Usergroup. Diese wird von Tobias Schmid geleitet. Damit ist nun also die Lücke zwischen München und Ulm geschlossen und ich freue mich auf eine gute Zusammenarbeit. Apropos Zusammenarbeit, ganz besonders freut es mich, dass ich am 14.10.2009 beim Gründungstreffen einen Vortrag zum Thema “Durchgängige Entwicklungsprozesse mit Visual Studio Team System” halten darf. Dann auf gute Nachbarschaft 
http://www.ug-augsburg.net/
 Mit Martin Woodward haben wir einen der weltweit bekanntesten Team System MVPs zu Gast der in seinem Vortrag über die neuen Möglichkeiten des Build Systems im TFS 2010 informieren wird. Dass sich beim Build in TFS2010 einiges getan hat, wird bereits aus der Auflistung der Hauptpunkte von Martins Vortrag ersichtlich. Es wird um Private Builds, Gated Checkins und um die neuen workflow-basierten Builddefinitionen gehen. Über TSUG-VE Die Team System User Group – Virtual Edition ist eine weltweite Usergroup zum Thema Team System. Die Treffen finden virtuell in Live Meeting statt. Weitere Informationen gibt’s unter http://www.tsug-ve.com.
Am 27.10.09 veranstaltet die .net Developer Group eine kostenlose Informationsveranstaltung rund um Visual Studio Team System 2010. Ein Tag voll gepackt mit wertvollen Informationen rund um die neue Version der Microsoft ALM-Plattform. Mit Visual Studio Team System 2010 führt Microsoft voraussichtlich Anfang nächsten Jahres eine neue Version seiner Entwicklungsplattform ein, die mit zahlreichen Neuerungen aufwartet. Diese neue Version wartet mit einer großen Zahl umfangreicher Neuerungen auf wie z.B.: - Architektur-Diagramme und UML-Support
- Erweiterte Funktionen für Test-Planung und Test-Durchführung
- Unterstützung von UI-Tests
- Verbesserte Verwaltung von Builds
- Verbesserte Verwaltung von Work Items
- Neue Reporting-Funktionen speziell für kleinere Teams
- Und vieles mehr
Um diese Umfangreichen Neuerungen alle vorstellen zu können, veranstaltet die .Net Developer-Group Ulm erstmalig einen ganztägigen Event um damit der Fülle von Funktionen auch gerecht zu werden. Dabei werden die beiden Referenten Christian Binder (http://blogs.msdn.com/cbinder) und Thomas Schissler (http://www.artiso.com/problog) nicht nur die neuen Funktionen vorstellen, sondern auch aufzeigen, welche Probleme aus dem Entwickler-Alltag damit gelöst werden können. Der Vortrag richtet sich dabei nicht nur an Entwickler und Projektleiter die bereits mit Team System arbeiten, sondern erläutert auch grundsätzliche Konzepte und bereits bestehenden Funktionen der Tools Visual Studio Team System und Team Foundation Server und bietet damit auch denjenigen einen guten Einstieg, die sich noch nicht intensiv mit Microsofts ALM-Plattform auseinandergesetzt haben. Für die Veranstaltung ist eine Registrierung erforderlich. Interessenten können sich unter http://www.dotnet-ulm.de/vsts2010 kostenlos registrieren.
Beim Installieren eines Team Foundation Server 2010 Beta 1 habe ich einen Fehler TF254038 bekommen. Beim Anlegen einer SharePoint Web Application auf dem TFS hat der Wizard behauptet ich hätte die SharePoint Extensions nicht installiert. Ich habe für den TFS und den SharePoint Server zwei getrennte Maschinen. Das Problem lag letztendlich darin, dass die Firewall auf der SharePoint Maschine den Zugriff auf die SharePoint Central Administration (Port 17012) geblockt hat. Nachdem ich den freigegeben habe, lief die Installation problemlos durch.
Wie in diesem Blog bereits an anderen Stellen erläutert, eignet sich das UIA (UI Automation Framework) sehr gut, um UI-Tests aufzubauen. Wer sich mit dieser Möglichkeit beschäftigt wird aber früher oder später auf das Problem stoßen, dass UIA Support bei WinForms Controls nicht flächendeckend gegeben ist, vor allem bei 3rd Party Controls sieht es da oft eher mau aus. Ich habe hier beschrieben, wie man mit einem ServerSide Provider diese Lücken selbst schließen kann. Das Standardvorgehen sieht dabei vor, dass man ein eigenes Control erstellt, das man dann von dem Ausgangscontrol ableitet. Diese Vorgehen ist in der Praxis allerdings nicht unproblematisch. Zum einen muss man die abgeleiteten Controls für jedes neue Release der Ausgangscontrols aktualisieren und zum zweiten ist es nicht gerade schön in einer bestehenden Anwendung alle Controls gegen die abgeleitete Variante austauschen zu müssen. Deshalb möchte ich hier einen alternativen Weg vorstellen. Die Idee beruht darauf, dass die Controls, denen es an Accesibility fehlt jeweils in ein Panel platziert werden und auf diesem Panel dann die entsprechenden Patterns implementiert werden. Das Panel kann die Operationen dann an das Control in seinem Bauch weiterleiten. Ich habe mal ein Beispiel für Janus Calendar Controls gebaut. Zunächst habe ich mir ein UIA-Panel erstellt, von dem ich dann die weiteren Panels für die spezifischen Controls ableiten kann. 1: using System; 2: using System.Drawing; 3: using System.Security.Permissions; 4: using System.Windows.Automation; 5: using System.Windows.Automation.Provider; 6: using System.Windows.Forms; 7: 8: namespace WindowsFormsApplication1 9: { 10: public partial class UIAPanel : Panel, IRawElementProviderSimple 11: { 12: public UIAPanel() 13: { 14: this.BackColor = Color.Yellow; 15: this.Height = 0; 16: this.Width = 0; 17: this.AutoSize = true; 18: } 19: 20: [PermissionSetAttribute(SecurityAction.Demand, Unrestricted = true)] 21: protected override void WndProc(ref Message m) 22: { 23: // 0x3D == WM_GETOBJECT 24: Int32 param = 0; 25: if (Int32.TryParse(m.LParam.ToString(), out param)) 26: { 27: if ((m.Msg == 0x3D) && (param == AutomationInteropProvider.RootObjectId)) 28: { 29: m.Result = AutomationInteropProvider.ReturnRawElementProvider( 30: Handle, m.WParam, m.LParam, (IRawElementProviderSimple)this); 31: return; 32: } 33: } 34: base.WndProc(ref m); 35: } 36: 37: #region IRawElementProviderSimple Members 38: 39: public object GetPatternProvider(int patternId) 40: { 41: if (patternId == ValuePatternIdentifiers.Pattern.Id) 42: { 43: return this; 44: } 45: else 46: { 47: return null; 48: } 49: } 50: 51: public object GetPropertyValue(int propertyId) 52: { 53: if (propertyId == AutomationElementIdentifiers.ClassNameProperty.Id) 54: { 55: return "CalendarPanel"; 56: } 57: else if (propertyId == AutomationElementIdentifiers.ControlTypeProperty.Id) 58: { 59: return ControlType.MenuBar.Id; 60: } 61: 62: if (propertyId == AutomationElementIdentifiers.HelpTextProperty.Id) 63: { 64: return "Help for CalendarPanel"; 65: } 66: 67: if (propertyId == AutomationElementIdentifiers.AutomationIdProperty.Id) 68: { 69: return this.Name; 70: } 71: 72: if (propertyId == AutomationElementIdentifiers.IsEnabledProperty.Id) 73: { 74: return true; 75: } 76: 77: else 78: { 79: return null; 80: } 81: } 82: 83: public IRawElementProviderSimple HostRawElementProvider 84: { 85: get 86: { 87: return AutomationInteropProvider.HostProviderFromHandle(Handle); 88: } 89: } 90: 91: public ProviderOptions ProviderOptions 92: { 93: get 94: { 95: return ProviderOptions.ServerSideProvider; 96: } 97: } 98: 99: #endregion 100: 101: } 102: }
Dieses Panel stellt einen ServerSide Provider zur Verfügung. Wir können nun von diesem Control ableiten und ein entsprechendes Pattern, z.B. das SetValue Pattern implementieren:
1: using System; 2: using System.Windows.Automation.Provider; 3: using System.Windows.Forms; 4: 5: namespace WindowsFormsApplication1 6: { 7: public partial class CalendarPanel : UIAPanel, IValueProvider 8: { 9: private Janus.Windows.Schedule.Calendar control; 10: public Janus.Windows.Schedule.Calendar Control 11: { 12: get 13: { 14: if (control == null) 15: { 16: if (this.Controls.Count > 0 && this.Controls[0].GetType() == typeof(Janus.Windows.Schedule.Calendar)) 17: control = (Janus.Windows.Schedule.Calendar)this.Controls[0]; 18: } 19: return control; 20: } 21: } 22: 23: #region IValueProvider Members 24: 25: public bool IsReadOnly 26: { 27: get 28: { 29: return false; 30: } 31: } 32: 33: public void SetValue(string value) 34: { 35: this.BeginInvoke((MethodInvoker)delegate() 36: { 37: DateTime date = DateTime.Parse(value); 38: Control.SelectionRange = new Janus.Windows.Schedule.DateRange(date, date); 39: }); 40: } 41: 42: public string Value 43: { 44: get 45: { 46: return Control.SelectionRange.End.ToShortDateString(); 47: } 48: } 49: 50: #endregion 51: } 52: }
Wenn wir nun das Calendar_Control nicht direkt auf unserer Form platzieren, sondern in einem solchen CalendarPanel ablegen, können wir eine Automatisierung über die UIA gegen dieses Panel implementieren. Was nun noch optimiert werden soll, ist dass die ganzen Controls nicht händisch in die jeweiligen Panels platziert werden sollen, sondern dies soll nach Möglichkeit automatisiert werden. der Ansatz hierbei ist, dass alle Controls auf der Form beim Laden untersucht werden und für die gewünschten Controls dynamisch entsprechende Panels erzeugt werden sollen, in die dann die Controls platziert werden. Dieser Ansatz bietet zudem den Vorteil, dass man die UIA-Panels nur dann nutz, wenn man UI-Test ausführen möchte. Bei der Release-Version sind diese dann nicht enthalten. Zwar unterscheidet sich dadurch Release und Test-Version geringfügig, jedoch sollten diese Implikationen vernachlässigbar sein, vor allem dann, wenn beim Entwickeln komplett auf die Panels verzichtet wird und diese wirklich nur für die UI-Tests genutzt werden.
Der Code dazu sieht dann so aus:
1: private void PlaceControlsIntoPanel(Control.ControlCollection controls) 2: { 3: Panel uiaPanel; 4: 5: foreach (Control automationControl in controls.OfType<Control>().ToList()) 6: { 7: switch (automationControl.GetType().ToString()) 8: { 9: case "Janus.Windows.CalendarCombo.CalendarCombo": 10: { 11: uiaPanel = new CalendarComboPanel(); 12: break; 13: } 14: case "Janus.Windows.Schedule.Calendar": 15: { 16: uiaPanel = new CalendarPanel(); 17: break; 18: } 19: default: 20: { 21: if (automationControl.HasChildren) 22: { 23: PlaceControlsIntoPanel(automationControl.Controls); 24: } 25: continue; 26: } 27: } 28: uiaPanel.Name = "p_" + automationControl.Name; 29: uiaPanel.Top = automationControl.Top; 30: uiaPanel.Left = automationControl.Left; 31: uiaPanel.Controls.Add(automationControl); 32: automationControl.Top = 0; 33: automationControl.Left = 0; 34: controls.Add(uiaPanel); 35: } 36: }
Wird die Anwendung dann inkl. Test-Client ausgeführt, sieht das so aus:
 Im Juni werden wir beim EMEA-Meeting der Team System User Group Virtual Edition Ed Blankenship als Sprecher haben. Ed ist MVP für Team System und Release Manager bei Infragistics, dem führenden Hersteller von UI-Komponenten. Er wird in seinem Vortrag über die Erfahrungen bei der Einführung von VSTS bei Infragistics berichten. Dabei werden die verschiedenen Bereiche wie Versionsverwaltung, Build Management, Work Item tracking, das Management globaler Teams, automatisiertes Testen und vieles mehr aus einer Anwendersicht beleuchtet. Ein wirklich sehenswerter Erfahrungsbericht aus der Praxis. Weitere Informationen unter www.tsug-ve.com.
Im Team Foundation Server werden Änderungen an den Inhalten der Workitems in einer Historie festgehalten. Diese Historie kann man auf jedem einzelnen Workitem einsehen. Mit einem kostenlosen Excel-Addin können diese Auswertungen auch massenhaft durchgeführt und so über ganze Projekte Auswertungen über die Historie erstellt werden. Dazu wird zunächst ein Zeitraum und ein Intervall ausgewählt (alternativ kann man auch einen bestimmten Zeitpunkt wählen):  Nun werden für jeden gewählten Zeitpunkt die Work Items in dem jeweiligen Zustand in eine Excel-Tabelle eingetragen. Diese kann nun sehr schön über eine Pivot-Tabelle oder ein Pivot-Chart ausgewertet werden um so den zeitlichen Verlauf bestimmter Kennwerte abzubilden.  Natürlich lassen sich solche Ergebnisse auch über das DataWarehouse im TFS ermitteln, jedoch besitzt dieses Tool zwei Vorteile: - Es ist wesentlich einfacher zu bedienen und übersichtlicher, so dass damit auch Ad-Hoc Reporting für Anwender möglich wird.
- Es grift auf alle Workitem-Daten zurück, nicht nur auf die, die im DataWareHouse konfigurierten. Einzige Ausnahme sind Links und Attachments, die in beiden Varianten nicht Teil der Historie sind.
Weitere Informationen und den kostenlosen Download gibtes unter http://www.alm-tools.de/?Product=5 Ein Video das die Fuinktionsweise des Tools demonstriert kann hier agezeigt werden.
Eigentlich versuche ich meinen Blog weitgehend werbefrei zu halten. Diesesmal möchte ich aber doch kurz auf die Seite www.alm-tools.de hinweisen, die mein Arbeitgeber artiso betreibt. Hier haben wir vor Kurzem eine Reihe neuer Tools rund um das Thema TFS und ALM (Application Lifecycle Management) veröffentlich, zum Teil kostenlos. Zudem gibt es hier inzwischen auch ein kleines Archiv mit Videos rund um das Thema das wir kontinuierlich ausbauen.
Mein Kollege Mark Bulmahn hat in einem Screencast ein Problem näher untersucht, das beim Merge in der TFS Source Countrol auftreten kann. Dabei geht es vor allem darum, dass Verschiebe-Operationen im Visual Studio Solution Explorer in der Source Control nicht als Verschiebe-Operation sondern als Delete und Add ausgeführt wird. Das führt dann zu Problemen bei einem späteren Merge.In dem Screencast sieht man, wie dieses Problem vermieden und auch wieder repariert werden kann.
Wenn schon mit Pre-Releases arbeiten, dann richtig habe ich mir gedacht und versucht den Team Foundation Server 2010 Beta 1 auf dem Windows 2008 Server R2 RC zu installieren. Nach einer kurzen Recherche im Internet bin ich auf diesen Blog-Post gestoßen. Mit den Informationen dort ist es mir tatsächlich gelungen, den TFS 2010 Beta1 und VSTS 2010 Beta1 auf dem Win2008R2 RC zu installieren. Damit komme ich nun auch auf meiner Demo-Maschine in den Genuss der Desctop-Experience von Win2008R2 
 Im Mai haben wir bei der TSUG-VE Ian Ceicis als Sprecher zum Thema Projekt Management mit TFS 2010. Er wird in seinem Vortrag die Neuerungen rund um das Workitem-Tracking in TFS 2010 vorstellen. Want to get the skinny on the latest enhancements coming in TFS 2010, come see demos of the updated MSF Agile template, the new Agile workbooks, the new Excel reports, and the Microsoft Project client improvements such as Hierarchical work items, rollups, and project summary tasks. This session will be packed with demos from Beta 1 and will be a great way to start getting familiar with the new tools coming in 2010. Bring your hardest questions, join the conversation, and walk away with the ability to see how your next project will run smoothly if you start using TFS 2010. This month's meeting is being presented by Ian Ceicys. Ian is a member of Microsoft's Global ALM Practice and an active member of the VSTS Rangers. Das Treffen findet am Donnerstag, 21.05.2009 um 19:00 statt. Weitere Infos unter http://www.tsug-ve.com
Unter http://msdn.microsoft.com/en-us/library/dd831853(VS.100).aspx steht inzwischen auch die Dokumentation für das .Net Framework 4 Beta 1 und Visual Studio 2010 Beta 1 zur Verfügung. Für die Beta 1 wird es nur eine Online-Version der Dokumentation geben, eine lokale Installation wird erst mit einer späteren Version verfügbar sein, was sicher bei einer Beta-Dokumentation auch Sinn macht.
Nachdem es bisher nur Gerüchte gab, nun ist es offiziell. Visual Studio 2010 Beta 1 wird noch heute für MSDN-User verfügbar sein. Für die Öffentlichkeit gibt es den Download dann ab Mittwoch.
Diesmal aus einer verlässlichen Quelle (Soma Somasegar, Corporate Vice President Microsofts)
Visual Studio 2010 and .NET FX 4 Beta 1 ships!
Update: Ich habe die Bits inzwischen runtergeladen. Da haben die Jungs wirklich noch einiges reingepackt gegenüber den früheren CTPs.
&
Mit der Version 3 des Design-Tools für WPF und SilverLight, Expression Blend bekommt nun endlich die Unterstützung für den Team Foundation Server um die Source-Dateien in der Versionsverwaltung abzulegen. Hierzu muss ein entsprechendes Hotfix installiert werden. Dann hat man im Project-View zusätzliche Icons die den Auscheck-Status der Dateien anzeigt und im Kontext-Menü befinden sich entsprechende Kommandos für die Versionsverwaltung.
Hinweis: Damit das beim ersten Start auch wirklich funktioniert, muss man im Visual Studio den Team Explorer wenigstens einmal gestartet haben und dort den Server registrieren. Sonst bekommt man die Meldung "Unable to determine workspace" im Expression Blend.
Beim Checkin ist auch die sehr nützliche Funktion zur Verknüpfung von Workitems beim Checkin verfügbar.
Damit kann Expression Blend nun endlich in den Entwicklungs-Prozess von Software-Anwendungen integriert werden und steht nicht nur als separates Design-Tool bereit.
 Nach rund einer Woche ist bereits die Hälfte der Plätze beim .Net Open Space Süd 2009 vergeben. Stand heute haben wir 33 Anmeldungen und es sind ein paar hochkarätige .Net Experten darunter. Wer also noch dabei sein will, sollte nicht zögern, sondern sich gleich auf die Teilnehmerliste eintragen. Wir sehen uns am 11/12. Juli in Ulm!
Auf einer neuen TFS-Instanz hatte ich eben ein seltsames Phänomen. Ich konnte das erste Team-Projekt problemlos anlegen. Dazu verwendete ich einen Team_Explorer mit einer Visual Studio Shell Installation auf dem Server. Als ich allerdings das zweite Projekt anlegen wollte, kam eine Fehlermeldung, dass mir die Berechtigungen auf den Reporting Services fehlen. Seltsam nur, dass es beim ersten Projekt geklappt hat und dazwischen nichts geändert wurde. Mit einem kleinen Trick konnte ich dann doch ein zweites Projekt anlegen, nämlich indem ich alle Projekte aus dem Team-Explorer entfernt habe. Dann konnte ich wieder genau ein neues anlegen. Die eigentliche Lösung für das Problem brachte aber die Installation des SP1 auf dem Server. Dabei ist zu beachten, dass das SP1 für den Team-Explorer nicht Bestandteil des Team Foundation Server SP1 ist, sondern des Visual Studio SP1. Also das Visual Studio SP1 installiert und danach lief es wunderbar.
 Letzte Woche habe ich bei der .Net Developer-Group Ulm einen Vortrag zum Thema “10 Gründe warum Software-Projekte fehlschlagen – und was hilft ALM"?” gehalten. Es gab zu diesem Vortrag eine reihe interessanter Diskussionen. Die Folien gibt’s hier zum herunterladen:
 Bei der TeamConf handelt es sich um eine Konferenz mit dem Focus auf Themen rund um VSTS und TFS. Da durfte ich natürlich nicht fehlen  Leider war mein Vortrag der letzte der Konferenz und dazu noch parallel zum VSTS 2010 Vortrag von Christian Binder. Dennoch fand sich eine interessierte Runde zum Thema “Requirements Management in leichtgewichtigen Prozessen” zusammen. Hier noch meine Folien zum Download:
 Termin: 19.05.2009 - 18:00 Uhr Veranstaltungsort:In den Räumen der artiso solutions GmbH Anfahrtsbeschreibung unter www.artiso.com Referent:Pedro Castelo Branco Lourenço Vortrag:Introducing F# As Developers, when we see a given demand, we always think on how to solve on a very imperative way (first do this, then this, finally that). Why not starting thinking on a more functional level, where we do not need to break one given task into so small imperative steps? This session will introduce Microsoft's new language F#, a typed functional programming language for the .NET Framework that combines the succinctness, expressivity and compositionality of functional programming with the runtime support, libraries, interoperability, tools, and object model of .NET. We'll take a look at why Microsoft is adding the language to the suite of those available on .NET and at some of simple language constructs that make programming in F# a dream. Pedro Castelo Branco Lourenço is a Brazilian guy that moved into Germany to work as Innovation manager at Savcor IT GmbH(http://www.savcor.de), MVP (Microsoft Most Valuable Professional) on C#, Microsoft Certified Professional Developer(Web & Windows), independent consultant to companies that build software using .Net platform, speaker in some well known technical events such as Tech Ed 2005, 2008(Brazil), Community Days, Developers On The Road, União.Net. Bachelor degree in computer science, member of moderator’s team of .Net Raptors community (www.dotnetraptors.com.br). During his free-time he is studying German to make his family life easier!
Zusammen mit Alexander Zeitler organisiere ich den .Net Opensapce Süd 2009. Seit heute ist die offizielle Homepage online und ich freue mich, die Veranstaltung hier ankündigen zu dürfen. Die besten Gespräche hat man fernab von einer festgelegten Agenda, bei einem Kaffee und beim "du". Dort gibt es keine Rollenaufteilung in Sprecher / Zuhörer, Entwickler / Administrator usw. und die Themen finden sich vor Ort ganz von selbst. Das ist die Idee vom .NET Open Space, die sich bereits 2008 in Leipzig bewährt hat. Hier sind alle gleich. Auch die Organisatoren halten sich im Hintergrund und moderieren nur ab und an etwas. Der .NET Open Space Süd 2009 läuft vom 11.07.2009 bis 12.07.2009. Welche Inhalte in dieser Zeit bearbeitet werden, wird vor Ort bestimmt, denn die Veranstaltung ist Open Space. Die Teilnahme ist kostenlos. Die Teilnehmer gestalten das Programm selbst. Erfahrungsaustausch ist das A und O und steht im Vordergrund. Mehr Informationen und Anmeldung unter: http://ulm.netopenspace.de Ich würde mich natürlich freuen, möglichst viele bekannten Gesichter und den einen oder anderen Leser meines Blogs bei diesem Event begrüßen zu dürfen. Ausdrücklich möchte ich betonen, dass dies nicht nur ein Event für Experten ist, sondern dass natürlich auch Teilnehmer willkommen sind, die sich noch nicht für solche halten. An dieser Stelle auch ein herzliches Dankeschön an Torsten Weber und Alexander Groß für die Unterstützung bei der Einrichtung der Website für den .NET Open Space Süd 2009.
 Im zweiten Teil wurde anhand eines kleinen Demos die konkrete Implementierung von WCF-Anwendungen erläutert. Es wurde ein Chat-System auf Basis der WCF erstellt. Das Demo gibt es hier zum Download. Außerdem möchte ich hier noch auf eine Einführung in die WCF hinweisen die man hier findet
 Beim ersten Termin wurden die Grundlagen zu verteilten Anwendungen im allgemeinen und der WCF im speziellen vermittelt.
Eines der coolsten Features in Windows 7 ist für mich der Problem Steps Recorder. Damit lassen sich Benutzeraktionen aufzeichnen und als MHT-File mit Screenshoots ausgeben. Diese Funktion eignet sich sehr gut um z.B. Installationsanleitungen oder auch Dokumentationen von Testdurchläufen zu erstellen. Hierzu wird einfach der Problem Steps Recorder über den Befehl PSR gestartet.  Nach einem Klick auf Start Record werden nun die Benutzeraktionen aufgezeichnet. Heraus kommt dann ungefähr so etwas: Problem Step 15: User left double click on "Name (editable text)" in "WorkItem_Manager_Open_1.0.0_Installer[1]"
Previous Next Problem Step 16: User left click on "Run (push button)" in "Open File - Security Warning"
Previous Next Problem Step 17: User left click on "Next > (push button)" in "artiso Workitem Manager Open"
Diese Aufzeichnungen funktionieren sowohl mit Web- als auch Windows-Anwendungen. Und natürlich können die erzeugten MHT-Files in Word oder anderen Editoren noch bearbeitet werden. So können z.B. überflüssige Zwischenschritte entfernt und Texte editiert werden. Es können auch währen des Aufzeichnungsvorgangs Kommentare erfasst und diesen ein bestimmter Bildausschnitt zugeordnet werden.
 Grade erst wurden die EMEA-Meetings der Team System User Group Virtual Edition ins Leben gerufen, schon können wir mit einem Highlight aufwarten. Für unser April-Meeting konnten wir Brian Harry als Sprecher gewinnen. Brian wird über die Internal Adoption von VSTS sprechen. Brian ist Technical Fellow und Manager der Product Unit für den team Foundation Server. Also gleich als Mitglied registrieren und am 16. April dabei sein! Weitere Informationen zum Meeting gibt’s unter www.tsug-ve.com.
 | Am 07. April um 18:00 Uhr findet das nächste Treffen der .Net Developer-Group Ulm statt. Diesesmal geht es im Rhamen der Microsoft Usergroup-Tour um das Thema Silverlight. Referent: Philipp Bauknecht Vortrag: Web & Silverlight Der Referent Philipp Bauknecht zeigt anhand eines E-Commerce-Szenarios, welche neuen Möglichkeiten in Silverlight und den Microsoft-Webtechnologien stecken. Er gibt Einblicke in die Bildbearbeitung mit Expression Design und in das Arbeiten und Programmieren mit Expression Blend. Weitere Themenschwerpunkte sind die Veröffentlichung von Videos sowie die wesentlichen Silverlight-Entwicklungsgrundlagen in Visual Studio. Anhand praktischer Beispiele demonstriert Philipp Bauknecht, wie sich die letzte Meile zum Anwender mithilfe von Silverlight durch interaktive Methoden überwinden lässt. Weitere Infos finden Sie hier… Freue mich auf zahlreiche Teilnehmer. Es gibt diesesmal wieder einen leckeren Imbiss der von der Fa. SOS Software Services gesponsort wird. |
Der Tatsache, dass Testen eine wichtige Bedeutung in der Software-Entwicklung hat, trägt Microsoft ja bereits seit einiger Zeit Rechnung indem eine spezielle Edition des Visual Studio für Tester generiert wurde. Diese Edition besitzt umfangreiche Funktionenzu verschiedenen Test-Methoden. Das Ranger-Team hat nun einen Quick Reference Guide veröffentlicht der auf 83 Seiten diese Funktionen beschreibt und verschiedene Best Practices anbietet. Hierbei sind die Erfahrungen eingeflossen, die Service Labs, ein großes Test-Center, bei der Adaption von Team Test gemacht hat. Das Dokument enthält viele wertvolle Hinweise, wie VSTT in der Praxis eingesetzt und individuell erweitert werden kann. Definitiv lesenswert für jeden, der etwas mehr über dieses Toolset erfahren möchte. Download VSTT 2008 Quick Reference Guide
Das Thema Test Driven Development oder auch Test First Developent gewinnt immer mehr an Beachtung. Keine Konferenz, keine Zeitschrift, kein Sprecher der was auf sich hält kommt um das Thema herum. Doch nach dem überzeugenden Vortrag sitzt man zu Hause im Büro vor einem leeren Project und wie nun anfangen? Hier scheitern bereits die ersten, weil entsprechende Publikationen oft zwar die Vorteile ausführlich schildern, aber nicht den Einstieg darstellen. Deshalb möchte ich hier einen entsprechenden Einstieg geben und mit einem wirklich leeren Projekt beginnen. Die Theorie um TDD will ich hier einfach weglassen. Hierzu gibt es bereits Informationen genug. Und wir werden verschiedene Vereinfachung vornehmen, über die Profis etwas die Nase rümpfen werden, aber damit erhalten wir ein einfaches und praktikable Einstiegsszenario. Zum Einsatz kommen hierbei die Testfunktionen von Visual Studio 2008 die ab der Professional Edition enthalten sind. Wir beginnen mit einer komplett leeren Solution. Die Frage, die nun im Raum steht, ist: Wie schreibe ich einen Test ohne eine Methode zu haben. Ein Unit-Test besteht ja im Prinzip darin, dass wir eine Methode aufrufen und den Rückgabewert mit einem Erwartungswert vergleichen. Der Test wird aber nicht einmal kompilieren, solange die Methode nicht definiert ist. Der Workaround an dieser Stelle sieht dann oft so aus, dass man von der Methode und ihrer Klasse erst einmal einen Stub anlegt der im wesentlichen eine “ThrowNotImplemented”-Exception wirft. Damit haben wir aber eigentlich schon mehr implementiert als nach dem TDD uns lieb ist. Ein etwas eleganterer Ansatz geht über die Definition von Interfaces. Diese Vorgehensweise eignet sich besonders gut bei einer komponentenorientierten Architektur mit einem Contract First Ansatz. Dabei werden die Schnittstellen der einzelnen Komponenten erst über Contracts (Interfaces) beschrieben bevor diese implementiert werden. Den TDD-Ablauf Rot > Grün > Refactor erweitern wir ein wenig. Damit ergibt sich folgende Abfolge: Contract definieren > Test implementieren > Rot > Funktion implementieren > Grün > Refactor D.h. wir erstellen in einem ersten Schritt einen Contract (genau genommen machen wir damit kein TDD sondern ein Test First. Beim TDD ist der Test das erste was erstellt werden muss, aber das ist in meinen Augen eher Haarspalterei, so funktioniert es einfach in der Praxis). Wir erstellen ein neues ClassLibrary-Projekt und erstellen dort ein Interface. 1: namespace Contracts 2: { 3: public interface IOrderCalculator 4: { 5: decimal CalculateShippinghCosts(decimal sum, decimal freeShippingMin, decimal shippingCosts); 6: } 7: }
Wir wollen hier ein überschaubares, aber auch nicht zu triviales Beispiel verwenden. Die Methode CalculateShippingCosts soll zu einem gegebenen Rechnungsbetrag Versandkosten hinzuaddieren, wenn ein bestimmter Mindestbetrag nicht erreicht ist. So damit haben wir den Contract erstellt. Nun wollen wir einen Test dazu erstellen. Das geht am schnellsten durch einen Rechts-Klick auf die Methode und dann “Create Unit-Tests”.
Hier wird standardmäßig ein neues Test-Projekt angelegt. Darin wird ein entsprechender Unit-Test generiert.
1: [TestMethod()] 2: public void CalculateShippinghCostsTest() 3: { 4: IOrderCalculator target = CreateIOrderCalculator(); // TODO: Initialize to an appropriate value 5: Decimal sum = new Decimal(); // TODO: Initialize to an appropriate value 6: Decimal freeShippingMin = new Decimal(); // TODO: Initialize to an appropriate value 7: Decimal shippingCosts = new Decimal(); // TODO: Initialize to an appropriate value 8: Decimal expected = new Decimal(); // TODO: Initialize to an appropriate value 9: Decimal actual; 10: actual = target.CalculateShippinghCosts(sum, freeShippingMin, shippingCosts); 11: Assert.AreEqual(expected, actual); 12: Assert.Inconclusive("Verify the correctness of this test method."); 13: }
Damit können wir den Test bereits zum ersten mal ausführen und er geht wie erwartet auf Rot. Aber Moment, wie funktioniert das. Wie kann der Test eine Methode auf einem Interface aufrufen? Es gibt ja noch keine Implementierung des Interfaces und ein Interface selbst lässt sich ja nicht instanziieren. Hier baut Visual Studio einen kleinen Workaround. In Zeile 4 im obigen Code sieht man, dass eine Instanz des target-Objektes über die Methode CreateIOrderCalculator() erstellt wird. Diese Methode wollen wir mal etwas genauer anschauen.
1: internal virtual IOrderCalculator CreateIOrderCalculator() 2: { 3: // TODO: Instantiate an appropriate concrete class. 4: IOrderCalculator target = null; 5: return target; 6: }
Hier wird das Objekt einfach mit null initialisiert. Ein einfacher, aber wirkungsvoller Workaround. Damit erreichen wir unser Ziel, dass der Test kompiliert aber fehlschlägt. Nach der Implementierung ersetzen wir das null einfach durch die entsprechende Initialisierung. Damit können wir nun unsere Testcases Implementieren.
1: [TestMethod()] 2: public void CalculateShippinghCosts_Sum_Below_FreeShippingMin() 3: { 4: IOrderCalculator target = CreateIOrderCalculator(); 5: Decimal sum = 1; 6: Decimal freeShippingMin = 10; 7: Decimal shippingCosts = 5; 8: // We are below min, so we have to add shippingCosts 9: Decimal expected = 6; 10: Decimal actual; 11: actual = target.CalculateShippinghCosts(sum, freeShippingMin, shippingCosts); 12: Assert.AreEqual(expected, actual); 13: } 14: 15: [TestMethod()] 16: public void CalculateShippinghCosts_Sum_Above_FreeShippingMin() 17: { 18: IOrderCalculator target = CreateIOrderCalculator(); 19: Decimal sum = 20; 20: Decimal freeShippingMin = 10; 21: Decimal shippingCosts = 5; 22: // We are above min, so we don't add shippingCosts 23: Decimal expected = 20; 24: Decimal actual; 25: actual = target.CalculateShippinghCosts(sum, freeShippingMin, shippingCosts); 26: Assert.AreEqual(expected, actual); 27: } 28: 29: [TestMethod()] 30: public void CalculateShippinghCosts_Sum_Equal_FreeShippingMin() 31: { 32: IOrderCalculator target = CreateIOrderCalculator(); 33: Decimal sum = 10; 34: Decimal freeShippingMin = 10; 35: Decimal shippingCosts = 5; 36: // We are equal min, so we don't add shippingCosts 37: Decimal expected = 10; 38: Decimal actual; 39: actual = target.CalculateShippinghCosts(sum, freeShippingMin, shippingCosts); 40: Assert.AreEqual(expected, actual); 41: }
Damit haben wir unser Szenario ausreichend beschrieben. Wir können nun an die Implementierung gehen.Dazu legen wir ein neues Projekt an in dem wir eine Klasse definieren die wir von unserem Interface ableiten.
1: namespace Components 2: { 3: public class cOrderCalculator : IOrderCalculator 4: { 5: public decimal CalculateShippinghCosts(decimal sum, decimal freeShippingMin, decimal shippingCosts) 6: { 7: // If sum is greater than Min then don't add shipping costs 8: if (sum > freeShippingMin) 9: return sum; 10: else 11: // else add shipping costs 12: return sum + shippingCosts; 13: } 14: } 15: }
Nun müssen wir unbedingt noch daran denken, die Initialisierung des Testobjektes in unserer Testmethode anzupassen.
1: internal virtual IOrderCalculator CreateIOrderCalculator() 2: { 3: IOrderCalculator target = new cOrderCalculator(); 4: return target; 5: }
Nun können wir die Tests ausführen.
Oh, ein Test schlägt fehl. Bei genauerer Betrachtung stellen wir fest, dass wir bei der Implementierung den Fall dass die Summe gleich der Grenze ist nicht richtig berücksichtigt haben. Also hat sich hier der TDD-Ansatz schon bewährt und wir können den Fehler beheben. Damit sind alle Tests grün und wir können weiter fortfahren. Wir könnten nun z.B. auf unserem Interface weitere Methoden definieren und dafür Tests anlegen.
Also eigentlich gar nicht so schwer das mit dem TDD, oder? Freue mich auf euer Feedback.
Die Solution gibt es zum Download.
Happy Testing!
Letzte Woche war ich als Trainer beim Team System Camp. Eine wirklich bemerkenswerte Veranstaltung! Schon der Veranstaltungsort selbst war bemerkenswert. Das Häckers Kurhotel in Bad Ems stellte einen durchaus würdigen Rahmen für die Veranstaltung dar und auch der Seminarraum hatte durchaus Stil: Die Verpflegung war dem Ambiente angemessen, Mittags und Abends ein vorzügliches 3-Gänge-Menü und auch das Rahmenprogramm passte. Mit Kart-Fahren, Casino-Besuch und weiteren Aktivitäten konnte ein paar Momente entspannt werden. Das war auch dringend nötig. Denn trotz all dieser Annehmlichkeiten kamen natürlich die Inhalte nicht zu kurz. Zwei Trainer auf 5 Teilnehmer ist sicher schon ein ungewöhnlicher Schnitt. Aber dass die Trainings von 9:00 Uhr bis 23:00 gehen ist schon heftig. Also wurde nach dem Kart-Fahren noch was gegessen und dann ging’s im Seminar-Raum weiter. So konnten die Teilnehmer sicher einen sehr guten Überblick über den Team Foundation Server und VSTS bekommen. Und durch die kleine Gruppengröße konnte auch auf individuelle Fragen ausführlich eingegangen werden. Mir hat’s jedenfalls viel Spaß gemacht und bin beim nächsten mal gerne wieder dabei.
Für alle die entweder in der Nähe von Wien leben oder die entsprechend großes Interesse am Thema VSTS haben um diese schöne Stadt auch mal zu besuchen, hier eine Ankündigung: Am 8. Mai 2009 wird im Microsoft Innovation Center (MIC) in Wien der Office (VSTO) Community Day statt finden. Hierbei geht es 1 Tag lang rund um Office Business Applications. Die Veranstaltung wird von Lars Keller und Mario Meir-Huber geführt. Die Themen sind: · Einführung in die VSTO · OpenXML: Das neue Office Format · VSTO Deployment · Sharepoint Workflows und Integration · Interaktionen in der "Office-Welt" mit .NET · Office plus Services Die Veranstaltung ist frei zugänglich, jedoch gibt es eine Limitierung auf 35 Teilnehmer. Anmelden kann man sich in dem extra für das Event aufgesetzten Wiki (http://www.vsto-taskforce.de/wikis/ocd/teilnehmer.aspx).
Die Integration von Visual Studio 2005 / 2008 mit dem TFS ist ideal gelöst. Jedoch gibt es auch noch andere Entwicklungs-Plattformen die keine direkte Integration mit dem Team-Explorer erlauben wie z.B. ältere Visual Studio Versionen und leider auch immer noch das SQl Server Management Studio. Diese IDEs überstützen doch recht häufig den sog. MSSCCI-Standard und es gibt bereits seit längerer Zeit einen entsprechenden MSSCCI-Provider für den TFS 2008. Dieser hatte bisher immer noch den nachteil, dass er reine Sourcecontrol Features unterstützt hat und z.B. das Verknüpfen von Workitems beim Checkin nicht möglich war. In der neuesten Version ist dies nun auch möglich und somit ist auch bei IDEs die den Team Explorer nicht integrieren ein komfortables Arbeiten mit dem TFS möglich. Ich habe hier mal ein Beispiel für das SSMS 2008. Zunächst muss der TFS MSSCCI-Provider unter Optionen eingestellt werden. Legt man nun ein Datenbankprojekt an, dann kann man das in gewohnter Art und Weise mit der Source Control verbinden und man erhält Fenster “Pending Checkins”. Führt man hier nun den Checkin aus, kommt der aus dem Team-Explorer bekannte Dialog Hier können nun z.B. Checkin-Kommentare angegeben oder Workitems verknüpft werden. Sogar die Checkin-Plicies funktionieren hier wie gewohnt. Damit ist ein komfortables und problemloses Arbeiten auch mit solchen Umgebungen möglich, die den Team-Explorer nicht direkt integrieren. Und damit wieder ein Grund mehr, nun endlich auf den TFS zu setzen und SourceSafe und Konsorten endlich in Rente zu schicken.
 Bei der Team System Usergroup – Virtual Edition (TSUG-VE) handelt es sich um eine weltweite Online-Community die sich auf die Themen Visual Studio Team System und Team Foundation Server konzentriert hat. Die Treffen finden dabei zeitgleich in SecondLife und LiveMeeting statt. SecondLife bietet den Vorteil, die sozialen Aspekte einer Community besser in der Online-Welt abzubilden, LiveMeeting wird als Präsentationssystem genutzt. Die virtuellen Treffen unterscheiden sich vom Ablauf und Inhalt kaum von denen entsprechender Offline-Communities. Während und nach den Vorträgen können ganz normal Fragen gestellt werden. Die Vorträge werden aufgezeichnet und stehen Mitgliedern im nachhinein im LiveMeeting-Portal zur Verfügung. Um die Vortragszeiten für die Teilnehmer rund um den Globus komfortabler zu gestalten, wurde nun eine europäische Sektion der TSUG-VE ins Leben gerufen. Diese Sektion organisiert Meetings in einer komfortablen Zeit für die EMEA-Zone (19:00 Uhr deutscher Zeit). Natürlich steht den Mitgliedern jederzeit die Möglichkeit offen, an den Treffen der US-Sektion oder für den Bereich Asian-Pacific (momentan im Aufbau) teilnehmen zu können oder die Videos nachträglich abzurufen ohne sich hierfür separat registrieren zu müssen. Alle Treffen werden in englischer Sprache abgehalten. Die Leitung der EMEA-Zone habe ich übernommen und würde mich freuen, in Zukunft mehr Mitglieder aus dem Europa begrüßen zu dürfen. Kritik und Anregungen zur Organisation sind sehr willkommen, da wir im Moment noch dabei sind Erfahrungen im Betreiben einer Online-Community sammeln.
 VISfire sit eine Charting-Komponente für Silverlight und WPF. Das coole daran ist, dass die Charts animiert werden können. Einen schnellen Eindruck bekommnt man über die Silverlight Chart Gallery. Die componente ist unter GPL und einer kommerziellen Lizenz verfügbar.
Wie so oft lautet die Antwort es kommt darauf an. Un hier bietet die Seite ShineDraw eine gute Vergleichsmöglichkeit. In der Gallery befinden sich zahlreiche Beispiele die sowohl in Silverlight als auch in Flash implementiert sind. Da kann man nicht nur das Ergebnis in beiden Varianten vergleichen sondern auch den Code der in der jeweiligen Technologie erforderlich ist. Darüber hinaus kann man sich den einen oder anderen effekt abschauen und sieht auch gleich wie der implementiert wird. Der Quellcode ist unter der GNU General Public License, Version 3 bereitgestelt. http://www.shinedraw.com/flash-vs-silverlight-gallery/
 Die Initiative Clean Code Developer (CCD) (http://www.clean-code-developer.de/) hat sich zum Ziel gesetzt bestimmte Grundsätze bei der Entwicklung von Software bei den Entwicklern besser zu verankern. Bei diesen Grundsätzen handelt es sich um Prinzipien, Regeln und Praktiken deren Einhaltung zu qualitativ höherwertigem Code führt. Grundsätzlich ist eine Schrittweise Einführung dieser Prinzipien, regeln und Praktiken unterteilt in Grade vorgesehen. Zu jedem Grad gibt es ein farbiges Armband, das den Träger zum Einen als CCD ausweist und ihn zudem stets daran erinnert diese Grundsätze in seiner täglichen Arbeit zu befolgfen. Mit Sefan Lieser und Ralf Westphal stehen hinter diesem Projekt zwei ausgewiesene Experten. Die .Net Developer-Group Ulm (www.dotnet-ulm.de) möchte diese Aktion unterstützen und ruft seine Mitglieder auf sich zu beteiligen. Beim nächsten Treffen am 19.03.09 wird diese Aktion im Detail vorgestellt und es besteht die Möglichkeit die Armbänder zu einem vergünstigten Preis zu erwerben. Zudem ist angedacht, dass sich die beteiligten regelmäßig nach den UG-Meetings austauschen und gegenseitig über Erfahrungen berichten und die Konzepte des CCD miteinander diskutieren. Natürlich freue ich mich auf eine rege Teilnahme und natürlich sind Gäste gerne willkommen. Nähere Infos unter http://www.dotnet-ulm.de/Cleancodedeveloper.aspx
 Bei unserem nächsten Treffen am 19.03 haben wir Gregor Biswanger und Robert Walter zu Gast. Diese werden in ihrem Vortrag verschiedene Aspekte zu Test Driven Development beleuchten. Nähere Infos gibts hier: http://www.dotnet-ulm.de/Treffen.aspx#19032009
 Am 16.03.09 geht ein neuer Webcast von mir online mit dem Thema "Team Build mit Custom Build Tasks erweitern". Ich möchte hier schon mal die entsprechenden Infos veröffentlichen. In TeamBuild lassen sich eigene Build-Task integrieren. Diese können sehr einfach erstellt werden. Hierzu wird eine Klasse erstellt und diese von Task abgeleitet. Im folgenden Beispiel wird ein Build-Task erstellt, der im Rahmen des Builds die Version der Anwendung setzt. Und zwar soll hier die Build-Nummer in der Versionsnummer der Assembly abgebildet werden. Dies bietet Vorteile, wenn zu einer bestimmten Anwendungsversion der entsprechende Build identifiziert werden soll. 1: using System; 2: using System.Collections.Generic; 3: using System.Text; 4: using Microsoft.Build.Utilities; 5: using Microsoft.Build.Framework; 6: 7: namespace Artiso.BuildTasks 8: { 9: /// <summary> 10: /// Creates a AssemblyVersion out of a BuildNumber 11: /// </summary> 12: /// <remarks> 13: /// AssemblyVersion.Minjor and AssemblyVersion.Minor will be defined fiexed in 14: /// the Build-Script. If the BuildNumber is Dev_Versioning_20090305.4 we use 15: /// two digit year and month for AssemblyBuildNumber and day and 3 digit BuildRevision 16: /// for AssemblyRevision. BuildRevisio 17: /// </remarks> 18: /// <example> 19: /// Dev_Versioning_20090305.4 => xx.yy.0903.05004 20: /// </example> 21: public class ExtractRevision : Task 22: { 23: #region [rgn] Fields(3) 24: private string buildRevision; 25: private string buildVersion; 26: private string buildNumber; 27: #endregion 28: 29: #region [rgn] Properties(3) 30: /// <summary> 31: /// Input Build Number 32: /// </summary> 33: [Required] 34: public string BuildNumber 35: { 36: set { buildNumber = value; } 37: } 38: 39: /// <summary> 40: /// Returns the sortened date of the build 41: /// </summary> 42: [Output] 43: public string BuildVersion 44: { 45: get { return buildVersion; } 46: } 47: 48: /// <summary> 49: /// Returns the Build Revision (number of build at this day 50: /// </summary> 51: [Output] 52: public string BuildRevision 53: { 54: get { return buildRevision; } 55: } 56: #endregion 57: 58: #region [rgn] Methods(1) 59: public override bool Execute() 60: { 61: buildVersion = "0"; 62: buildRevision = "0"; 63: 64: if (buildNumber != null && buildNumber.Contains(".")) 65: { 66: string[] buildNumberParts = buildNumber.Substring(buildNumber.LastIndexOf('_')+1).Split('.'); 67: 68: // Dev_Versioning_20090305.4 -> 0903.02005 69: // use year (2 digits) and mont for buildversion 70: buildVersion = buildNumberParts[0].Substring(2, 4); 71: 72: // use day and number of build in this day for build revision 73: buildRevision = buildNumberParts[0].Substring(6) + buildNumberParts[1].PadLeft(3, '0'); 74: } 75: return true; 76: } 77: #endregion 78: } 79: }
Das Property BuildNumber wird als Input-Parameter verwendet und mit dem Attribut [Required] versehen. Darüber kann die BuildNumber in unseren Task übergeben werden. Durch das Attribut [Output] werden die beiden Properties BuildVersion und BuildRevision als Rückgabewerte definiert. Beim Ausführen des Builds wird die Methode Execute aufgerufen. Hier werden nun aus der Build-Number die entsprechenden Informationen extrahiert und diese dann in BuildVersion und BuildRevision zurückgeschrieben. Dies ist natürlich nur ein einfaches Beispiel, aber mit diesen Grundlagen können nun beliebige Build-Tasks definiert werden. Im nächsten Schritt schauen wir uns an, wie wir diesen Custom Build Task nun in unseren Build-Prozess einbinden. Hierzu kopieren wir zunächst die Assembly in einen entsprechenden Ordner. Hier bietet sich an unter c:\Program Files\MSBuild einen entsprechenden Ordner anzulegen und dort die Assemblies abzulegen.
Nun muss das Build-Script entsprechend angepasst werden. Diese liegt in der Quellcode-Verwaltung und muss zum Bearbeiten zuerst aus- und danach wieder eingechecked werden. Um diesen Vorgang zu vereinfachen empfehle ich die TFS Sidekicks (http://www.attrice.info/downloads/index.htm) die direkt im Kontextmenü des TeamExplorers entsprechende Kommandos einfügt. Das nun ausgecheckte PROJ-File kann nun bearbeitet werden.
1: <?xml version="1.0" encoding="utf-8"?> 2: <!-- DO NOT EDIT the project element - the ToolsVersion specified here does not prevent the solutions 3: and projects in the SolutionToBuild item group from targeting other versions of the .NET framework. 4: --> 5: <Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> 6: 7: <!-- Do not edit this --> 8: <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" /> 9: <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/> 10: 11: <UsingTask AssemblyFile="$(MSBuildExtensionsPath)\ArtisoBuildTasks\ArtisoBuildTasks.dll" 12: TaskName="ExtractRevision"/> 13: 14: <PropertyGroup> 15: <!-- Assembly version properties. Adjust here Major and Minor Version--> 16: <AssemblyMajorVersion>1</AssemblyMajorVersion> 17: <AssemblyMinorVersion>3</AssemblyMinorVersion> 18: <AssemblyBuildNumber>1</AssemblyBuildNumber> 19: <AssemblyRevision>1</AssemblyRevision> 20: </PropertyGroup> 21: ...
In Zeile 11 wird unser BuildTask entsprechend registriert. In Zeile 9 werden noch weitere Build-Tasks registriert. Hier gereicht es uns zum Vorteil, dass Team-Build auf MSBuild basiert. D.h. es können entsprechende Tasks für MSBuild problemlos integriert werden. Diese gibt es in großer Zahl für sehr viele Anwendungsbereiche zum großen Teil frei Verfügbar zum Download. Wir verwenden hier die MSBuild Community Tasks ( http://msbuildtasks.tigris.org/). Wir werden aus diesem Paket Aktionen verwenden.
In den Zeilen 14 bis 20 wird eine sog. PropertyGroup angelegt. Darin werden einzelne Properties definiert und mit Default-Werten vorbelegt. Diese Properties lassen sich mit Variablen innerhalb eines Software-Codes vergleichen. Die AssemblyMajorVersion und AssemblyMinorVersion werden hier festgelegt. AssemblyBuildNumber und AssemblyRevision werden wir im weiteren Verlauf überschreiben.
Am Ende des Scripts direkt vor dem schließenden </Project>-Tag wird nun ein Target-Block eingefügt.
1: ... 2: <Target Name="AfterGet"> 3: <ItemGroup> 4: <AssemblyInfoFiles Include="$(SolutionRoot)\**\assemblyinfo.cs" /> 5: </ItemGroup> 6: 7: <Message Text="Get Revision Number from BuildNumber "$(BuildNumber)"." /> 8: <ExtractRevision BuildNumber="$(BuildNumber)"> 9: <Output TaskParameter="BuildRevision" 10: PropertyName="AssemblyRevision" /> 11: <Output TaskParameter="BuildVersion" 12: PropertyName="AssemblyBuildNumber" /> 13: </ExtractRevision> 14: 15: <!-- Update all the assembly info files with generated version info --> 16: <Message Text="Modifying AssemblyInfo files under "$(SolutionRoot)"." /> 17: <Attrib Files="@(AssemblyInfoFiles)" Normal="true" /> 18: <FileUpdate Files="@(AssemblyInfoFiles)" 19: Regex="AssemblyVersion\(".*"\)\]" 20: ReplacementText="AssemblyVersion("$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision)")]" /> 21: <FileUpdate Files="@(AssemblyInfoFiles)" 22: Regex="AssemblyFileVersion\(".*"\)\]" 23: ReplacementText="AssemblyFileVersion("$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision)")]" /> 24: <Message Text="AssemblyInfo files updated to version "$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision)"" /> 25: </Target> 26: 27: </Project>
Über den Namen des Target-Blocks mit "AfterGet" wird festgelegt, dass dieser Block ausgeführt wird, nachdem der Build-Prozess die Quelldateien aus der Versionsverwaltung geholt hat. Genau zu diesem Zeitpunkt wollen wir unsere Versionierung anpassen. In den Zeilen 3 bis 5 erstellen wir eine ItemGroup die alle assemblyinfo.cs Dateien unserer Solution enthält. In diesen Dateien wollen wir die Version anpassen. In Zeile 7 wird eine Meldung in das Build-Log geschrieben. Dies ist hilfreich, um Fehler im Ablauf des Scriptes besser einordnen zu können.
In den Zeilen 8 bis 13 wird nun unser Build-Task aufgerufen. Wir übergeben die Buildnummer $(BuildNumber) in den Parameter BuildNumber und lesen die Output-Parameter aus und schreiben diese in AssemblyRevision bzw. AssemblyBuildNumber (die Properties die wir weiter oben definiert hatten). In Zeile 17 heben wir den Schreibschutz der AssemblyInfo-Dateien auf und in den folgenden Zeilen wird mit Hilfe eines Ersetzen-Vorgangs die Version in den AssemblyInfo-Dateien ersetzt. Für diese Aktionen nutzen wir die Community Build Tasks.
Damit können wir nun die Version unserer Anwendung bei jedem Build entsprechend setzen.
In einem nächsten Schritt wollen wir den Build-Task nun noch erweitern um das Build-Result in einer ZIP-Datei zu verpacken und diese anschließend per Mail zu versenden. Auch hierbei greifen wir auf die MSBuild Community Tasks zurück. Das entsprechende Target-Tag fügen wir einfach nach dem zuvor definierten ein. Als Name geben wir "AfterCompile" an so dass diese Aktionen nach dem Kompilieren ausgeführt werden. 1: <Target Name="AfterCompile">
2: <CreateItem Include="..\Binaries\Release\**\*.*" Exclude="..\Binaries\Release\**\*.pdb;..\Binaries\Release\**\*codeanalysis*"> 3: <Output ItemName="ZipFiles" TaskParameter="Include"/> 4: </CreateItem> 5: 6: <Message Text="Zipping Buildresult to \\tfs\deploy\BuildDemo\BuildDemo_$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision).zip" /> 7: 8: <Zip ZipFileName="\\tfs\deploy\BuildDemo\BuildDemo_$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision).zip" 9: Files="@(ZipFiles)" 10: WorkingDirectory="..\Binaries\Release\"/> 11: 12: <Mail SmtpServer="tfs" 13: To="tschissler@tfs" 14: From="build@tfs" 15: Subject="BuildDemo v$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision) released" 16: Body="A new version of the BuildDemo was released. Please find the newest files attached to this mail. You can also download them from the download folder." 17: Attachments="\\tfs\deploy\BuildDemo\BuildDemo_$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision).zip"/> 18: </Target>
Hier sammeln zunächst alle Dateien aus dem Build-Drop-Verzeichnis exklusive der PDB- und Codeanalyse-Dateien In Zeilen 8-10 werden diese Dateien in ein ZIP-File verpackt dem wir im datei-Name die Version mitgeben. Anschließend versenden wir eine e-Mail der wir dieses ZIP-File als Attachment anhängen.
Als zweite Variante wollen wir im Rahmen des Builds ein Click-Once Paket erstellen. Die Herausforderung bei der Erstellung des ClickOnce-Paketes ist dass dort die Deployment-Url hinterlegt werden muss. Vor allem wenn verschiedene Pakete für unterschiedliche Kunden erstellt werden sollen, ist dies nur durch eine Automatisierung im Rahmen des Builds sinnvoll handelbar. Hierzu ersetzen wir den AfterCompile-Target durch folgendes Script:
1: <Target Name="AfterCompile"> 2: <!-- Publish using ClickOnce --> 3: <Message Text="modify Publish directory for $(SolutionRoot)" /> 4: <!-- Update directory where to publish the project --> 5: <ItemGroup> 6: <ProjectFiles Include="$(SolutionRoot)\Source\Dev\BuildDemo\BuildDemo.csproj" /> 7: </ItemGroup> 8: <PropertyGroup> 9: <PublishDir>\\tfs\Deploy\BuildDemo\ClickOnce\</PublishDir> 10: <InstallUrl>\\tfs\Deploy\BuildDemo\ClickOnce\</InstallUrl> 11: </PropertyGroup> 12: <Attrib Files="@(ProjectFiles)" Normal="true" /> 13: <FileUpdate Files="@(ProjectFiles)" 14: Regex="<PublishUrl>.*</PublishUrl>" 15: ReplacementText="<PublishUrl>$(PublishDir)</PublishUrl>" /> 16: <FileUpdate Files="@(ProjectFiles)" 17: Regex="<InstallUrl>.*</InstallUrl>" 18: ReplacementText="<InstallUrl>$(InstallURL)</InstallUrl>" /> 19: 20: <MSBuild Projects="@(ProjectFiles)" 21: Properties="PublishDir=$(PublishDir);ApplicationVersion=$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision)" 22: Targets="Publish" /> 23: 24: </Target>
In den Zeilen 5 bis 7 lesen wir das csproj-File der Anwendung in eine ItemGroup. Anschließend definieren wir zwei Properties für PublishDir und InstallUrl. Diese werden dann über eine Ersetzung in die csproj-Datei eingefügt. Anschließend wird ein MSBuild-Task gestartet der das ClickOnce-Paket erstellt und an der angegebenen PublishDir und mit der Versionsnummer veröffentlicht.
Das Ganze wird in dem genannten Webcast Live demonstriert. Über Feedback würde ich mich sehr freuen.
Details zur Veranstaltung: Team Build mit Custom Build Tasks erweitern [1032405249] - Microsoft Deutschland GmbH
Letzte Woche war ich auf dem MVP-Summit in Seattle. Für mich war es die erste Veranstaltung dieser Art und so wusste ich nicht genau, was mich erwarten würde. Ich wurde aber auf jeden Fall positiv überrascht. Es war für mich eine Woche voller neuer Infos und Eindrücke und es war auch sehr cool, die anderen Team System MVPs persönlich zu treffen und sich mit denen auszutauschen. Gerade im Bereich Team System tut sich momentan extrem viel und so hatten wir ein Non-Stop Programm und um VSTS 2010. Non Stop heißt, dass es bereits am Sonntag Nachmittag mit einer MVP 2 MVP Session losging, wo einige MVPs Erfahrungen aus ihrer Praxis darstellten. Das war extrem interessant und ich konnte viele neue Ideen mitnehmen. Am Montag und Dienstag hatten wir dann von 8:00 bis 18:00 Uhr volles Programm. Verschiedene Mitglieder der Product-Group stellten die einzelnen Bereiche von VSTS 2010 vor. Volles Programm heißt in diesem Fall Sessions ohne Pause (wir hatten selbst Lunch-Sessions, wo man sich am Buffet etwas zu Essen holte und dann sich setzte um der aktuellen Session zu folgen). Neno hat wirklich ein anspruchsvolles Programm für uns zusammen mit der Product-Group zusammengestellt. Da war wirklich extrem viel Content drin. Am Mittwoch waren dann Key-Notes angesagt, die ich allerdings etwas enttäuschend fand und damit wirklich keine Zeit verschwendet war, hatten wir am Mittwoch Nachmittag nochmals Sessions bei denen wir mit Sam Guckenheimer über die zukünftige Entwicklung diskutierten. Eine wirklich extrem interessante Woche mit vielen neuen Eindrücken. Es wird wohl etwas dauern, bis ich das alles verarbeitet habe, der geneigte Leser wird aber dann die Ergebnisse an dieser Stelle lesen können Im Moment kann ich das Ganze nur so zusammenfassen: VSTS 2010 is a realy big, big thing! Hier noch ein paar Impressionen: Blick von der Space Needle auf Seattle  Die Team-System MVPs  Sam Guckenheimer  Brian Harry Karaoke mit Live-Band bei der Party Steve Balmer bei seiner Key-Note
Gestern und heute hatte ich auf der BASTA zwei Vorträge. Hier die Folien dazu:
 Ich bin reichlich spät dran, die VSOne ist schon seit einer Woche vorbei. Hier aber nun endlich meine Folien zu meinen Vorträgen
 Zusammen mit Christian habe ich einen Webcast zum Thema Testing Practices aufgenommen. In dem Webcast werden zunächst verschiedene Testmethoden vorestellt und anschließend werden verschiedene Aspekte einer Teststrategie diskutiert wie z.B. Methoden zur Testfall-Ermittlung. Der komplette Abstract lautet: Qualität spielt in Software-Projekten eine immer größere Rolle. Ein wesentlicher Aspekt für Software-Qualität ist das Testen. Der Webcast stellt zunächst kurz die verfügbaren Testmethoden in Visual Studio vor und zeigt anschließend Aspekte einer Test-Strategie auf. Darüber hinaus wird die Integration mit dem Team Foundation Server kurz beleuchtet und es werden Methoden zur Testfallermittlung beschrieben. Über ein Feedback zum Webcast würde ich mich freuen. http://www.microsoft.com/germany/msdn/webcasts/library.aspx?id=1032405240
An einem kleinen Beispiel möchte ich kurz erläutern, wie PEX parametrisierte Unit-Tests nutzt und wie man diese nutzen kann um bestimmte Test-Szenarien abzubilden. Wir nehmen einen kleinen Codeausschnitt um uns das mal anzusehen: 1: public class TotalSum 2: { 3: private double total = 0; 4: 5: public double CalculateTotals(List<cOrderPosition> OrderPositions, double Rebate) 6: { 7: if (OrderPositions == null) 8: return 0; 9: 10: foreach (cOrderPosition orderPos in OrderPositions) 11: { 12: if (orderPos.Amount > 0 && orderPos.SinglePrice > 0) 13: total += orderPos.Amount * orderPos.SinglePrice; 14: } 15: 16: if (Rebate > 0) 17: total = total * (1 - Rebate); 18: 19: return total; 20: } 21: 22: public class cOrderPosition 23: { 24: public int ProductID { get; set; } 25: public double Amount { get; set; } 26: public double SinglePrice { get; set; } 27: } 28: }
Auf den ersten Blick scheint da alles OK zu sein. Mal sehen was PEX daraus jetzt macht.
Zunächst sehen wir, dass PEX 3 Probleme mit Object Creations hat. Für den ersten Fall lassen wir PEX einfach automatisiert eine Factory erstellen indem wir auf "Accept/Edit factory" klicken. Für die Liste müssen wir ebenfalls eine Factory erstellen. Diese Factory wollen wir jetzt noch anpassen:
1: [PexFactoryMethod(typeof(List<TotalSum.cOrderPosition>))] 2: public static List<TotalSum.cOrderPosition> Create(int NumberOfItems) 3: { 4: List<TotalSum.cOrderPosition> list = new List<TotalSum.cOrderPosition>(NumberOfItems); 5: if (NumberOfItems > 10) 6: NumberOfItems = 10; 7: 8: for (int i = 0; i < NumberOfItems; i++) 9: { 10: list.Add(new TotalSum.cOrderPosition() 11: { 12: ProductID = i + 1, 13: SinglePrice = new Random().NextDouble() * 10, 14: Amount = new Random().NextDouble() * 10 15: }); 16: } 17: 18: return list; 19: }
Abhängig von der Anzahl Items die als Parameter übergeben wird, wird die Liste mit entsprechend vielen Elementen befüllt. Nun erhalten wir Ergebnisse bei der Exploration.
Und es sind alle grün. Also alles OK? Jetzt kommt der parametrisierte Unit-Test in's Spiel. Dazu müssen wir erst mal die Test generieren. Dazu einfach alle Einträge markieren und rechts auf "Save..." klicken.
1: [TestMethod] 2: [PexGeneratedBy(typeof(TotalSumTest))] 3: public void CalculateTotals04() 4: { 5: TotalSum totalSum; 6: List<TotalSum.cOrderPosition> list; 7: double d; 8: totalSum = TotalSumFactory.Create(); 9: list = ListFactory.Create(1); 10: d = this.CalculateTotals(totalSum, list, 0); 11: Assert.AreEqual<double>(42.232177096754121, d); 12: }
Wenn wir uns eine der generierten Testmethoden mal genauer anschauen, dann erkennen wir dass in Zeile 9 unsere ListFactory aufgerufen wird und in Zeile 10 wird eine Methode CalculateTotals aufgerufen. Bei dieser Methode handelt es sich um unseren parameterisierten Unit-Test der in der .cs-Datei abgelegt ist. Dieser parametrisierte Unit-Test nimmt Input-Werte engegen und ruft damit die eigentliche Funktion auf. Man kann den parametrisierten Unit-Test eigentlich mit einem datengetriebenen Test vergleichen, mit dem Unterschied dass die Daten nicht aus einer Datenquelle kommen sondern von den jeweiligen Testmethoden übergeben werden.
Wir können den parametrisierten Unit-Test selbst anpassen und auch Asserst einfügen. Was wir nun hier tun wollen, ist die eigentliche Test-Methode zwei mal aufzurufen und zu prüfen, ob beide Ergebnisse übereinstimmen. Bei gleichen Eingangswerten sollte dies ja der Fall sein. Der parametrisierte Unit-test sieht dann ungefähr so aus.
1: [TestClass] 2: [PexClass(typeof(TotalSum))] 3: [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentException), AcceptExceptionSubtypes = true)] 4: [PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))] 5: public partial class TotalSumTest 6: { 7: [PexMethod] 8: public double CalculateTotals( 9: [PexAssumeUnderTest]TotalSum target, 10: List<TotalSum.cOrderPosition> OrderPositions, 11: double Rebate 12: ) 13: { 14: double result = target.CalculateTotals(OrderPositions, Rebate); 15: double result2 = target.CalculateTotals(OrderPositions, Rebate); 16: Assert.AreEqual(result, result2); 17: return result; 18: } 19: }
Diese Prüfung wird nun für alle Testmethoden ausgeführt. Und wie sieht das Ergebnis aus?
Wir erhalten nun einen Fehlerfall. Wenn man sich den Code der Test-Methode nochmals genauer anschaut, stellt man fest, dass die lokale Variable total beim erneuten Aufruf nicht zurückgesetzt wird - ein klassischer Fehler. Wenn wir die Variable in der Methode zurücksetzen, dann werden unsere Testfälle auch alle erfolgreich sein.
Somit haben wir mit Hilfe von PEX einen gängigen Fehler gefunden der in Real-World-Projekten sicher im Code selbst nicht so offensichtlich wäre.
Ich habe in einem früheren Post bereits einige Beispiele für den Einsatz von PEX beschrieben. ich möchte nun in loser Reihe weitere Erkenntnisse die ich beim Experimentieren mit PEX gewinne hier veröffentlichen. Heute möchte ich mich mit Overflow-Exceptions beschäftigen. Anlass war eine Diskussion mit Nico. Als erstes Beispiel wollen wir uns mal folgenden Code ansehen: 1: public decimal Calc(decimal Value, bool Increase) 2: { 3: if (Increase) 4: return Value+1; 5: else 6: return Value-1; 7: }
Für eine komplette Codeabdeckung muss PEX eigentlich nur den Boolean-Parameter Increase berücksichtigen. Der Parameter Value kann eigentlich beliebig gewählt werden, auf die Code-Abdeckung hat der keinen Einfluss. Aber natürlich erkennt man dass es natürlich auch Fälle gibt in denen die Methode eine OverflowException wirft, nämlich bei value = decimal.MaxValue, Increase = true und value = decimal.MinValue, Increase = false.
Das erfreuliche ist, dass mit der aktuellen Version (0.9.40105.0) PEX zusätzlich zur Codeabdeckung auch Grenzwerte berücksichtigt:
Bei einem anderen Beispiel funktioniert das leider (noch) nicht.
1: public decimal ToDecimal(double Value) 2: { 3: return (decimal)Value; 4: }
Hier wird leider keine Grenzwertbetrachtung gemacht, die ja zu einer Exception führen würde da der Wertebereich von decimal kleiner ist als der von double.

Hier hatte ich beschrieben, wie man die Test-Results aus Visual Studio nach Excel übertragen kann. Heute möchte ich ein Tool vorstellen, das es erlaubt, TRX-Files nach HTML zu konvertieren. Zunächst speichert man das Test-Result in ein TRX-File. Dies geht über den Button "Export Test Run Results". Anschließend kann man mit dem Tool trx2html das HTML-File erstellen. trx2html ist ein Open-Source Projekt von CodePlex. Es wird als Commandozeilen-Tool ausgeführt und als Parameter wird einfach das TRX-File angegeben. Als Ergebnis wird nun ein HTML-File erstellt das die Testergebnis entsprechend dokumentiert und auch einige Drill-Down-Funktionen bietet: Durch einen Klick auf das rote Kreis-Icon neben einem der Test kann z.B. ein Stack-Trace eingeblendet werden. trx2html - Home
Bei Unit-Tests bietet die Code-Coverage eine gute und einfache Möglichkeit zu prüfen, ob durch die definierten Test-Cases alle Code-Pfade in einer Methode wirklich durch Tests ausgeführt werden. Dies hilft beispielsweise dabei, noch fehlende Test-Cases zu identifizieren. Auch mit manuellen Tests ist es möglich, eine Code-Coverage Analyse durchzuführen um auch hier fehlende Test-Cases zu ergänzen. Das folgende Beispiel zeigt eine mögliche Vorgehensweise. Zunächst wird davon ausgegangen, dass ein maueller Test spezifiziert ist. Dieser kann z.B. so aussehen: Nun wird ein Unit-Test erzeugt. Im Unit-Test wird eine Test-Methode angelegt die der Main-Methode der zu testenden Anwendung entspricht: 1: [TestMethod()] 2: [STAThread] 3: public void FrmMainConstructorTest() 4: { 5: Application.EnableVisualStyles(); 6: Application.SetCompatibleTextRenderingDefault(false); 7: Application.Run(new FrmMain()); 8: }
Anschließend muss geprüft werden, ob die Code Coverage analyse für die gewünschten Assemblies aktiviert ist (Menü Test / Edit Test Run Configurations / Local Test Run)
Wird nun der Test gestartet, öffnet sich die Testanwendung. Hier werden nun die einzelnen Test-Schritte gemäß Testspezifikation ausgeführt. Anschließend wird die Test-Anwendung beendet. Dies schließt automatisch auch den Test ab. Nun cann die Code-Coverage ausgewertet werden:
Und natürlich lassen sich auch die durchlaufenen und nicht durchlaufenen Code-Zeilen farblich kennzeichnen.
Den ganzen Ablauf wird in folgendem Video auch nochmals detailliert gezeigt:
 Beim nächsten Treffen der .Net Developer-Group Ulm dürfen wir diesesmal Dariusz Parys begrüßen, der zum Thema “Architektur der Datenanbindungsschicht, insbesondere ADO.NET Data Services und Entity Framework” spricht. Der Abstract verspricht schon mal einen sehr spannenden Abend: LINQ to SQL, ADO.NET, Entity Framework, Entity Data Model, REST mit ADO.NET Data Services oder Serialisierung mit WCF ? – neben einem Überblick über die Alternativen und detailliertere Darstellung des Entity Frameworks wird darauf eingegangen, welche Kriterien beim O/R-Mapping zur Bewertung zur Verfügung stehen und diskutiert, welcher Nutzen darin liegt, die Datenanbindung von einer technischen Ebene auf eine logische zu heben. Ích glaube das dürfte ein Themengebiet sein mit dem im Moment jeder Entwickler in irgendeiner Weise käpft und so dürfte sich Dariusz schon mal auf eine ganze Reihe von Fragen einstellen (Mir selbst fallen da schon eine ganze Reihe ein). Wer also Interesse an dem Thema hat, ist herzlich eingeladen am Dienstag 17.02.2008 um 18:00 zu uns zu kommen. Weitere Infos unter: http://www.dotnet-ulm.de
In manchen Fällen ist es wünschenswert, eine Liste mit den Tests aus einem Projekt auszudrucken. Leider gibt es hierzu in Visual Studio keine direkte Funktion, aber ein kleiner Trick hilft hier: 1.) Im TestView die gewünschten Spalten einblenden 2.) Gewünschte Tests markieren und dann im Kontext-Menü "Copy" auswählen 3.) In Excel einfügen, fertig! Das selbe funktioniert übrigens auch aus den Test Results, leider ohne Icons :-( 
Als Blogger freut man sich natürlich immer über Kommentare. Das ist bei diesem Medium eine der wenigen Möglichkeiten Feedback zu bekommen. Und nun musste ich feststellen, dass auf meinem Blog leider seit einger Zeit die Kommentare nicht mehr richtig zugestellt werden. Dafür ein großes Entschuldigung an alle, die in letzte Zeit sich die Mühe gemacht haben und meine Beiträge kommentiert haben. Sorry, das ihr keine Antwort erhalten habt. Lasst euch nicht entmutigen, ich freue mich über jeden Kommentar und jetzt sollten die auch wieder bei mir ankommen.
Die Team System User Grroup - VE ist eine virtuelle Usergroup die zwei mal im Monat ein Treffen hat in deren Rahmen Vorträge rund um das Thema Team System gehalten werden. Die Treffen finden virtuell in Second Life und über Live Meeting statt. Für Europäer ist das jeweils zweite Treffen zeitlich günstig am Samstag Nachmittag. Team System User Group - Virtual Edition
Auf MSDN gibt es einen neuen Bereich zu Team System. Die Seite ist in einer ersten Iteration veröffentlicht und wird nun kontinuierlich mit weiterem Content ergänzt. Hier sind die Inhalte wesentlich übersichtlicher aufbereitet als auf den alten Seiten. Wer also mit Team System arbeitet oder das vorhat, einfach mal vorbeischauen. Feedback zu der Seite ist sehr willkommen und kann hier abgegeben werden. Team System Home auf MSDN
 Endlich gibt es von PEX nun auch eine kommerziell nutzbare Lizenz. Bisher stand nur eine Academic License zur Verfügung, mit der nur “gespielt” werden durfte. Aber welche Aussagekraft hat denn eine Bewertung des Tools mit Demo-Projekten? Jetzt kann man PEX nun endlich auch auf Real-World-Projekte loslassen. http://research.microsoft.com/en-us/projects/pex/downloads.aspx
Bisher war für mich das Pflegen meiner verschiedenen Signaturen im Outlook immer ein Horror. Wenn ein neuer Rechner eingerichtet wurde, musstden die Signaturen wieder mühsam angelegt werden und wenn es Änderungen gab, dann grauste es mich schon davor, diese auf allen Instanzen anzupassen. Dank Lars kenne ich nun aber einen einfacheren Weg. Die Signaturen werden nämlich einfach im Filesystem abgelegt und zwar unter %UserProfile%\AppData\Roaming\Microsoft\Signatures. Diese Files lassen sich einfach auf einen neuen Rechner kopieren (sogar bei laufendem Outlook sind die Signaturen dann sofort verfüpgbar!) oder sie können zwischen mehreren Rechnern einfach synchronisiert werden. Super cool. Vielen Dank Lars, du hast mir das Leben wirklich erleichtert!
Inzwischen gibt es eine verstärkte Diskussion, ob der Windows 2008 Server nicht die bessere Workstation ist. Sicher hängt das vom jeweiligen Einsatzgebiet ab. Bei mir war es so, dass ich für den Team Foundation Server einen Server als Betriebssystem auf meinem Demo-Rechner benötigt habe. Dabei wollte ich aber nicht auf den Komfort und das Design von Vista verzichten und auch Features wie z.B. den Sidebar nutzen. Die erste gute Nachricht ist, dass man Win2008 so anpassen kann, dass es sich optisch kaum von Vista unterscheiden lässt und die zweite gute Nachricht ist, dass es mit Hilfe eines kleinen Tools ganz einfach ist und schnell geht. Selbst Aero ist damit möglich. http://www.win2008workstation.com/wordpress/2008/07/17/windows-server-2008-workstation-converter/
In den letzten Wochen war ich recht viel mit Vorträgen auf Tour. Inzwischen hat sich eine stattliche Anzahl von Vortragsthemen angesammelt. Unten sieht man eine Übersicht. Wer Interesse hat, dass ich einen Vortrag halte, darf sich gerne bei mir melden. Über das INEATA Speaker Bureau bin ich für INEATA UserGroups auch kostenlos zu buchen. Ansonsten würde ich mich auch über Feedback freuen. Sollte ich noch ein Thema mit aufnehmen, wer hat schon einen Vortrag von mir gehört und wie hat er gefallen etc. | Titel | Dauer | Abstract | | Qualitätsmanagement mit VSTS und TFS | 1 Std - 3 Std. | Qualität spielt bei Software eine immer stärkere Rolle. Gleichzeitig werden immer effizientere Entwicklungsprozesse angestrebt. Dies lässt sich nur mit geeigneter Tool-Unterstützung und passenden Lösungen zu Prozessen und Software-Architektur erzielen. Mit Visual Studio Team System und Team Foundation Server stehen Tools zur Verfügung, die nicht nur eine entsprechende Testunterstützung bietet, sondern auch komplette Qualitätsprozesse unterstützt. Der Vortrag zeigt, wie Qualitätsprozesse durch TFS unterstützt werden. Anschließend werden verschiedene Testmethoden vorgestellt und einige Praxis-Tipp für deren Einsatz gegeben. | | Agile Development Process - Ein Architekturbasierter Entwicklungsprozess | 1 Std Vortrag, 1 Std. Demo | Moderne Software-Anwendungen werden immer komplexer. Dadurch gewinnt auch die Software-Architektur immer mehr an Bedeutung. Wartbarkeit, Testbarkeit, Erweiterbarkeit und Teamentwicklung sind nur einige Aspekte, die eine gute Architektur unterstützen soll. Doch diese Aspekte können nicht durch ein einzelnes Architekturkonzept abgedeckt werden. Dieser Vortrag stellt verschiedene Architektur-Patterns wie Komponentenorientierung, Contract First Design, Service-Orientierung und UI Driven Development vor. Und vor allem wird gezeigt, wie diese Konzepte zu einem praxiserprobten Entwicklungsprozess verbunden werden können. | | Mehrschichtige Architekturen mit .Net | 1 Std. | Mehrschichtige Architekturen sind heute eigentlich oft Standard, vor allem bei verteilten Anwendungen. Allerdings wird diese Architektur oftmals zu sehr an technischen Belangen ausgerichtet. Die Session zeigt, wie man mehrschichtige Architekturen plant und diese flexibel und leitungsfähig aufbaut. Es werden verschiedene praxiserprobte Patterns vorgestellt. | | Build-Management mit Team Foundation Server | 1 Std. | Mit Team Foundation Server steht ein leistungsfähiges integriertes Buildsystem zur Verfügung. Wie man dieses im Rahmen der Projekte nutzt und welche Vorteile sich daraus ergeen zeigt diese Session. Darüber hinaus wird der Einsatz verschiedener Buildsteps zum Deployment, Versionierung etc. vorgestellt. | | Testing Practices mit VSTS und TFS | 1 Std. - 3 Std. | VSTS bringt eine ganze Reihe von Testmethoden. Insbesondere die Edition für Tester bietet verschiedene Testarten. Die Implementierung der unterschiedlichen Testarten ist inzwischen hinlänglich beschrieben. Wie diese Tests in Real-World-Projekte eingesetzt werden, um tatsächlich die Qualität zu verbessern, beschreibt der Vortrag ebenso wie die Lösung von Real-World-Problemen. Dabei werden Themen wie die Bereitstellung von Testumgebungen, Testplanung und Testdurchführung sowie Testdokumentation ebenso beleuchtet wie die Frage, in welchen Fällen eine Edition für Tester notwendig ist, wo es mögliche Alternativen gibt und wie verschiedene Akteure innerhalb des Projekts wie z.B. Fachabteilungen eingebunden werden. | | UI-Testing mit UI Automation | 1 Std. - 1,5 Std. | Unit-Testing und Web-Testing verbreiten sich mit VSTS und anderen Testing-Tools immer mehr. Was diese Testmethoden jedoch nicht abdecken, ist quasi die „letzte Meile“, die Oberfläche der Anwendungen. Um diese in Tests einzubinden sind entweder teure Tools erforderlich, oder man nutzt das weitgehend unbekannte UI Automation Framework, das Bestandteil des .NET 3.0 Frameworks ist. Der Vortrag erläutert zunächst, wie man mit Hilfe des UI Automation Frameworks Windows- und WPF-Anwendungen kontrollieren kann. Anschließend werden diese Methoden in Unit-Tests integriert, um damit automatisierte UI-Tests aufzubauen. Als krönender Abschluss wird ein UI-Test-Recorder implementiert, mit dem UI-Aktionen aufgezeichnet und automatisiert in Unit-Test überführt werden können. Der Vortrag beschreibt neben den Möglichkeiten auch Grenzen des UI Automation Frameworks und mögliche Lösungen. | | Closing Tool-Gaps in your Development Process with the TFS API | 1 Std. | The efficiency of development processes is based on a powerful and integrated tool support. But development processes are individual and no standard software can fulfill this integration 100%. With the Team Foundation Server API we have a powerful technology to extend the standard functionality for our needs. As an example in this session we will live code a tool to organize workitems in a hierarchical way and you will learn how this can improve your development process. Also you will get some additional visions about how you can use TFS Extensibility to make real cool things with your TFS. | | Lücken in der Tool-Unterstützung für IhrenEntwicklungsprozess mit der TFS API schließen | 1 Std. | Die Effizienz eines Entwicklungsprozesses hängt stark von einer leistungsfähigen und integrierten Entwicklungsplattform ab. Aber Entwicklungsprozesse sind individuell an keien Standardsoftware kann eine 100%ige Integration gewährleisten. Mit der Team Foundation Server API steht eine leistungsfähige Technologie zur Verfügung, die es erlaubt, die Standard-Funktionen des Team Foundation Servers bedarfsgerecht zu erweitern. Als Beispiel wird in dieser Session ein live ein Tool erstellt, das eine hierarchische Organisation von Workitems ermöglicht. Und es wird erläutert, wie damit Entwicklungsprozesse verbessert werden können. Darüber hinaus werden verschiedene Visionen aufgezeigt wie man mit Hilfe der TFS Extensibility richtig coole Sachen für den TFS machen kann. | | Durchgängige Entwicklungsprozesse mit Visual Studio Team System | 1 Std. | Mit Visual Studio Team System bietet Microsoft eine leistungsfähige Entwicklungsplattform die den gesamten Lebenszyklus eines Entwicklungsprojektes vom Requirement Management bis zum Systembetrieb abbilden kann. Der Vorteil dabei ist, dass alle wichtigen Elemente des Prozesses in einem System integriert und so Verbindungen zwischen den einzelnen Prozessartefakten hergestellt werden können. Der Vortrag zeigt wie ein kompletter Entwicklungsprozess mit VSTS abgebildet werden kann. Als Beispiel wurde hierzu bewusst ein agiler Prozess gewählt der vor allem auch für kleinere Entwicklungsteams geeignet ist. Dabei werden die wesentlichen Funktionselemente von Visual Studio Team System und Team Foundation vorgestellt und deren Nutzung im Prozess gezeigt. | | Reporting mit dem TFS | 1 Std. | Der Team Foundation Server bietet umfangreiche Projekt-Kennzahlen. Neben Prozess- und Qualitätskennzahlen sowie verschiendenen Planungskenngrößen können auch weitere Daten wie z.B. zum Build-Prozess oder aus der Quellcode-Verwaltung ausgewertet werden. Hierbei stehen mit den SQL Server Reporting Services und Excel zwei leistungsfähige Tool zur Verfügung, diese Daten zu visualisieren. Der Vortrag zeigt anhand verschiedenen Beispielen auf, wie individuelle Auswertungen erstellt werden können und welche Möglichkeiten sich damit eröffnen. | | UI Driven Development - Von der UI zur Anwendung | 0,5 Std. - 1 Std. | Missverständnisse und unterschiedliche Interpretation von Spezifikationen sind in Software-Projekten heute an der Tagesordnung. Was also tun, um dieses zu vermeiden? Die Spezifikation noch detaillierter formulieren? Einen anderen Ansatz geht UI Driven Development. Hierbei wird die Oberfläche einer Anwendung als Spezifikationsbestandteil aufgefasst. Der Clou dabei ist, das bei diesem Vorgehensmodell nicht irgendwelche Prototypen entstehen, die die spätere Funktionalität und Aufbau nur vage wiedergeben, sondern "erlebbare" Oberflächen. Und diese Oberflächen können in das Finale Projekt 1:1 übernommen werden, so dass der Investierte Aufwand direkt dem Projekt zugute kommt. Der Vortrag erläutert Architekturkonzepte und Vorgehensmodelle die UI Driven development ermöglichen. | | Organisation von Entwickler-Teams | 0,5 Std. - 1,5 Std. | Dieser Vortrag ist als Interactive Session konzipiert. Die Teilnehmer können in einer moderierten Diskussionsrunde sich austauschen über verschiedene Erfahrungen mit unterschiedlichen Modellen der Team-Organisation. Der Moderator stellt dabei im Laufe der Veranstaltung verschiedene Aspekte der Team-Organisation und mögliche Vorgehensweisen vor und stellt diese zur Diskussion. Dabei werden Themen wie Generalisten vs Spezialisten, Kommunikation im Team, Mitarbeitermotivation und vieles mehr ausführlich diskutiert. | | Automatisierte Generierung von Unit-Tests mit PEX | 0,5 Std. | PEX - ein Tool von Microsoft Research verspricht nichts weniger als die automatisierte Generierung von Unit-Tests und zwar mit dem Ziel einer möglichst vollständigen Code-Abdeckung. Wie PEX funktioniert und inwieweit dieses Versprechen eingehalten werden kann, zeigt dieser Vortrag. Darüber hinaus wird auch beleuchtet, in welchen Szenarien PEX eine wirklich sinnvolle Unterstützung bei Real-Projekten sein kann und wie man es einsetzen kann. | | 10 Gründe warum Software-Projekte fehlschlagen können – und was hilft ALM? | 1 Std. | Für Probleme in Software-Projekten gibt es vielfältige Gründe. Viele dieser Gründe können jedoch auf suboptimale oder gar nicht vorhandene Prozesse zurückgeführt werden. Der Vortrag analysiert die häufigsten Ursachen für fehlgeschlagene Projekte und zeigt mögliche Lösungen auf. Dabei wird auch beleuchtet wie Application Lifecycle Management organisiert sein muss um hier zu unterstützen. | | TDD Quick Start | 0,5 Std. | Test Driven Development - Eines der häufigsten Buzz-Wörter wenn es um das Thema Software-Testing geht. Umso erstaunlicher, dass es in der Praxis aber relativ selten zum Einsatz kommt. Häufig liegt es auch daran, dass TDD an gewisse Vorbedingungen in Bezug auf Architektur, Prozesse etc. gebunden ist. Der Vortrag versucht einen Schnelleinstieg in TDD zu geben, wobei versucht wird diese Vorbedingungen weitgehend auszublenden um dem Zuhörer einen möglichst schnellen und unkomplizierten Einstieg zu bieten. Die hierzu erforderlichen Kompromisse werden jedoch am Ende des Vortrages aufgezeigt und ein Ausblick auf optimierte Lösungen gegeben. |
Wo finde ich eine User-Group in meiner Nähe? Diese Frage beantwortet der Usergroup-Kompass. Eine wirglich schöne Idee wie ich finde. User Group-Kompass
In der vergangenen Woche war ich bei gleich 3 User-Groups in Bonn, Stuttgart und bei uns in Ulm und habe dort meinen Vortrag zu architekturbasierten Entwicklungsprozessen gehalten. Dabei ging es im Kern darum, dass moderne Software.Projekte bestimmte Anforderungen an Prozesse haben. Der Vortrag zeigte hier zunächst verschiedene dieser Anforderungen an Testbarkeit, Team-Arbeit und die Definition von Spezifikationen. Anschließend wurden verschiedene Architekturkonzepte vorgestellt um dann aufzuzeigen, wie diese Konzepte die Prozessanforderungen erfüllen können. Zum Abschluss wurde dann das Ganze mit einem Demo-Projekt anschaulicher dargestellt. Die Folien und das Demo kann hier heruntergeladen werden:
 Das patterns & practices Team hat einen Application Architect Guide veröffentlicht. Das 365 Seiten umfassende Dokument kann kostenlos von CodePlex heruntergeladen werden und beschreibt Architekturansätze für Windows, Web, Mobile und andere Anwendungen. Neben theoretischen Grundlagen werden auch explizite Guidelines für verschiedene Design-Aspekte einer Anwendung beschrieben. Absolut empfehlenswert! patterns & practices: Application Architecture Guide 2.0 (The Book) - Home
 Gestern Abend habe ich bei der .Net Developer Group Braunschweig einen Vortrag zu Agile Development Process - Ein architekturbasierter Entwicklungsprozess gehalten. Während des Vortrages und vor allem am Ende gab es eine sehr gute und interessante Diskussion. Bei dem Vortrag habe ich demonstriert wie wir bei uns im Unternehmen verschiedene Architekturpatterns verwenden um Prozessanforderungen zu unterstützen. Dabei kommen bewährte Konzepte wie Komponentenorientierung, Contract First und mehrschichtige Architektur zum Einsatz, aber auch von uns angepasste bzw. neu entwickelte Methoden. Die Folien und das Demo kann hier heruntergeladen werden:
Der Team Foundation Server verwendet in den Versionen bis 2008 eine XML-Datei um den Build-Prozess zu steuern. Diese Datei wird Build Project File genannt und wird in der Versionsverwaltung abgelegt um vom Buildcomputer genutzt werden zu können. Jeder der diese Datei aber schon manuell bearbeitet hat, kennt das umständliche Vorgehen umd die Date erst aus der Quellcode-Verwaltung auszuchecken, und nach dem Bearbeiten wieder einzuchecken. Einfacher geht das mit den TFS Sidekicks, die direkt im Context-Menü des Team-Explorers eine Checkout und Checkin-Funktion für das Project-File anbietet. Darüber hinaus bieten die TFS Sidekicks noch weitere sehr nützliche Funktionen, auf jeden Fall ist das Tool einen näheren Blick wert. Attrice Corporation - Team Foundation Sidekicks
Today I had my second talk on the TechEd in Barcelona. It was about closing tool gaps in development processes and using the TFS API. Thanks to all attendees joined my session. We had some very interesting discussion at the end, and I got a lot of positive feedback like “This was what I was looking for”. For all here comes the promised downloads for the slides and demos. Feel free to use them in either way. And here the link to download WorkitemManager. At www.alm-tools.com you can download the Open version which is free and also the source code. And if you are interested in one of the tools I showed, please just send me an e-Mail to tschissler (at) artiso (.) com.
Ok, not to confuse you, I'm not going to blog English from now on. But I did a session on UI-Testsing with the UI Automation Framework and to provide slides and demo-code to the attendees I use this blog post. The session went fairly well from my point of view and I had some really interesting discussions on this topic after the session. I hope those who have joined me got some good information about how you can do UI-testing today with completely free tools. I'll provide some pictures later because I cannot read them from my camera right now. Here comes the downloads:
Mit ein wenig Verspätung wurden die TFS Power Tools October 2008 nun released. Dafür wurden aber noch ein paar wichtige Bugs gefixed. Damit stehen nun die größten Power-Tools zur verfügung, die jemals veröffentlicht wurden. Über die Features habe ich bereits hier gebloggt. ich denke damit werden ein paar wichtige Lücken geschlossen und durch die Explorer Integration wird TFS für weitere Szenarien interessant. Download details: Team Foundation Power Tools
Der artiso Workitem Manager ist ein Tool mit dem sich Workitems hierarchisch organisieren lassen. Diese hierarchische Organisation bietet verschiedene Vorteile. Neben einer besseren Strukturierung und einer erhöhten Übersichtlichkeit vor allem auch eine visuelle Traceability. Damit ist gemein, dass durch die Hierarchie sichtbar wird welche Tests und Implementierungsaufgaben einem Feature zugeordnet sind. Die ist z.B. sehr hilfreich, wenn sich das Feature ändert zu erkennen, welche Workitems auf mögliche Auswirkungen überprüft werden können. Wie hierarchische Workitems in Projekten hilfreich eingesetzt werden, habe ich zusammen mit Christian Binder in diesem MSDN-Webcast erörtert. Leider bringt der TFS in der Version 2008 diese Hierarchie nicht von Haus aus mit. Deshalb hat artiso den Workitem Manager entwickelt. Diesen gibt es nun auch als Open-Version. Die Open-Version ist kostenlos und wird auch als Source-Code bereitgestellt. Wie sich der Workitem Manager Open zur Vollversion unterscheidet kann man der unten stehenden Funktionsmatrix entnehmen. Weiter unten gibt's noch eine Screenshot. Den Donload für das Setup und den Source-Code findet man unter http://www.alm-tools.de. Gerne freue ich mich über euer Feedback zu dem Tool.  
Seit kurzem bin ich stolzer Besitzer einer Microsoft Wireless Notebook Presenter Mouse 8000 (was für ein Name!). Auf meinem Notebook hatte ich aber ständig das Problem dass die Meldung "HDI data has stopped working" kam. Zwar funktionierte das System ohne Probleme aber die Meldung war extrem nervig, vor allem bei Demos und Vorträgen. Nach einigem suchen bin ich dann auf einen Forum-Thread gestossen der genau für dieses Problem eine Lösung beschreibt. Der entscheidende Post hier nochmals kurz zitiert: I was having the same problem with my bluetooth microsoft wireless notebook presenter mouse 8000. The problem is created by an application in the HP quick launch Buttons. I removed the application from the launch buttons.
go to:
C:\Program Files\Hewlett-Packard\HP Quick Launch Buttons
move the following files to a backup folder on your computer:
HidActn.dll Hiddata PushHid.dll
Then restart you computer and you should not have the errors and the other things on your laptop should still be available. "HID data has stopped working" - bluetooth mouse error - Vista Hardware Devices
Wie ich hier bereits gepostet habe, verschmilzt Microsoft die Visual Studio Team System Development Edition mit der Database Edition, aus meiner Sicht eine wirklich gute Lösung. Um dieses Thema treten aber immer wieder Fragen auf, so dass ich hier mal die wichtigsten gesammelt habe und natürlich auch beantworte. F: Wie installiere ich die zusätzliche Edition? A: Auf MSDN steht den Abonenten die jeweils andere Edition nun zusätzlich zum Download zur Verfügung. Diese kann hier heruntergeladen und dann einfach zusätzlich zur bestehenden Installation installiert werden. Die zusätzlichen Funktionen integrieren sich dann in die bestehende Installation. Ein gemeinsames Installationspaket ist momentan nicht geplant. Mit VS2010 werden die beiden Editionen dann als gemeinsames Paket ausgeliefert. F: Für welche Editionen gilt diese Option? A: Die Option gilt sowohl für die 2005er als auch für die 2008er Editionen, im Detail also für: Visual Studio 2005 Team Edition for Software Developers with MSDN Premium Subscription Visual Studio 2005 Team Edition for Database Professionals with MSDN Premium Subscription Visual Studio Team System 2008 Development Edition with MSDN Premium Subscription Visual Studio Team System 2008 Database Edition with MSDN Premium Subscription
F: Wie verhält sich das mit Servicepacks? A: Nach der Installation der zusätzlichen Edition müssen die Servicepacks erneut installiert werden. Weitere Informationen finden sich auch auf der FAQ-Seite zum Merge. FAQ - MSDN Subscribers with Visual Studio Team System Development Edition or Database Edition
Das neueste CTP zu Visual Studio 2010 (Codename Rosario) steht nun zum Download bereit. Das CTP wird als VPC Image bereitgestellt. Mit Visual Studio 2010 kommen viele neue interessante Features. Vor allem im Bereich Testing und Architektur hat sich hier vieles getan. Ich werde mit diesem CTP beginnen, die einzelnen Funktionen näher zu beleuchten und sicher in nächster Zeit den einen oder andern Blogbeitrag zu diesem Thema schreiben. Es gibt mit dem CTP verschiedene Aktivierungs-Meldungen. Diese können jedoch meistens einfach ignoriert werden, das Image läuft ganz normal weiter. Download details: Visual Studio 2010 and .NET Framework 4.0 CTP
Christian Binder hat eine sehr Übersichtliche Darstellung über die verschiedenen VSTS-Sessions auf dem Technical Summit in Berlin zusammengestellt. Die Map stellt nicht nur die dort live vorgestellten Sessions zusammen, soondern auch bereits bestehende und in Kürze erscheinende Webcasts zu dem Thema. Die Map zeigt auch, dass wir versucht haben unsere Inhalte auf dem Technical Summit so aufeinander abzustimmen, dass sowohl EInsteiger als auch fortgeschrittene Anwender sich ein möglichst komplettes Bild von VSTS machen kann. Die WebCast sind thematisch entsprechend eingeordnet und können als Vorbereitung bzw. zur Vertiefung zu den Live-Sessions genutzt werden. Danke Christian, endlich mal eine übersichtliche Darstellung der verschiendenen Inhalte!
Was bedeutet was? Christian Binder's Weblog : Alle Visual Studio Teamsystem Session auf dem Technical Summit 2008 im Überblick
Microsoft Research hat vor kurzer Zeit PEX zum freien Download veröffentlicht. Hinter diesem unscheinbaren Kürzel verbirgt sich ein Tool das absolut genial und beeindruckend ist und klar mach, warum Microsoft ein research center unterhält. Das Tool verspricht nichts weniger als die automatische Generierung von Unit-Tests und den dazugehörigen Testcases um eine möglichst hohe Code-Abdeckung zu erzielen. Detaillierte Informationen bietet das Whitepaper, wer sich auf die schnelle einen Einblick verschaffen möchte findet einen Überblick im Folgenden (na ja, für einen Überblick ist der Post vielleicht doch ein wenig lang geraden, aber ich konnte mich nicht bremsen vor Begeisterung): Darf ich vorstellen - PEX Gegeben sei folgende Methode die getestet werden soll: 1: public string SimpleTest(int x1, int x2) 2: { 3: if (x1 > x2) 4: return "x1 > x2"; 5: if (x1 < x2) 6: return "x1 < x2"; 7: else 8: return "x1 == x2"; 9: }
Für das versierte Auge eines Entwicklers ist sofort klar, da brauchen wir 3 Testcases um eine vollständige Code-Abdeckung zu erzielen. Mal sehen, was PEX daraus macht. Zunächst mal muss PEX heruntergeladen und installiert sein. Dann kann man einfach einen "Parameterized Unit Test Stub" erzeugen. Dazu in der Methode rechts klicken und den Befehl aus dem Pex-Menü auswählen.
Im folgenden Dialog können Sie verschiedene Parameter angeben. Das wichtigste hier ist das Testprojekt in dem der Stub erzeugt werden soll.
Der erzeugte Stub sieht dann so aus:
1: /// <summary> 2: /// This class contains parameterized unit tests for Calculation 3: /// </summary> 4: [TestClass] 5: [PexClass(typeof(Calculation))] 6: public partial class CalculationTest 7: { 8: [PexMethod] 9: public string SimpleTest( 10: [PexAssumeUnderTest]Calculation target, 11: int x1, 12: int x2 13: ) 14: { 15: string result = target.SimpleTest(x1, x2); 16: return result; 17: // TODO: add assertions to method CalculationTest.SimpleTest(Calculation, Int32, Int32) 18: } 19: 20: }
Bei diesem Stub handelt es such um eine Vorlage für einen parameterisierten Unit-test. Toll, und was lässt sich damit nun machen? Wir können eine "Exploration" starten.
Diese Exploration versucht nun Input-Parameter zu finden die zu einer möglichst 100%igen Code-Abdeckung führen. Und hier beginnt nun die Magic von PEX. Ohne unser Zutun findet PEX 3 Kombinationen von Input-Parametern die tatsächlich eine komplette Code-Abdeckung erzielen- WOW! Dazu analysiert PEX wirklich den von uns erstellten Code und kann daraus definieren, mit welchen Input-Parametern die einzelnen noch nicht abgedeckten Zweige erreicht werden können.
Und das schönste, PEX baut uns automatisch 3 Unit-Tests die diese Testcases implementieren:
1: [TestMethod] 2: [PexGeneratedBy(typeof(CalculationTest))] 3: public void SimpleTest01() 4: { 5: string s; 6: Calculation calculation = new Calculation(); 7: s = this.SimpleTest(calculation, 1, 2); 8: Assert.AreEqual<string>("x1 < x2", s); 9: } 10: 11: [TestMethod] 12: [PexGeneratedBy(typeof(CalculationTest))] 13: public void SimpleTest02() 14: { 15: string s; 16: Calculation calculation = new Calculation(); 17: s = this.SimpleTest(calculation, 1879212556, 1879212556); 18: Assert.AreEqual<string>("x1 == x2", s); 19: } 20: 21: [TestMethod] 22: [PexGeneratedBy(typeof(CalculationTest))] 23: public void SimpleTest03() 24: { 25: string s; 26: Calculation calculation = new Calculation(); 27: s = this.SimpleTest(calculation, 256, 254); 28: Assert.AreEqual<string>("x1 > x2", s); 29: }
Diese Unit-Tests können wir nun starten und sehen, dass diese wie erwartet alle erfolgreich sind.
Damit haben wir einen Test automatisiert erstellt, der sicherstellen kann, dass diese Methode ihr Verhalten nach Außen für die aktuell definierten Test-Cases nicht verändert. Damit können ungewollte Änderungen an der Methode erkannt und beseitigt werden. Ob die Methode allerdings ihre Aufgabe korrekt erledigt, kann PEX natürlich nicht testen. Haben wir die Funktionsweise einer Methode allerdings einmal validiert, kann PEX nun sehr einfach dieses Verhalten prüfen. Und natürlich eignet es sich auch sehr gut um mögliche Test-Cases zu definieren. Es müssen in diesem Fall dann nur noch die einzelnen Ergebnisse je Test validiert werden.
Ändern wir die Methode ab, so dass sich ihr Verhalten ändert, dann alarmiert uns der entsprechende Test.
Soweit sogut - Und was geht sonst noch?
Wenn wir nun ein gewünschte Änderung der Funktionalität implementieren, wie kann PEX dann damit umgehen? Zunächst würden wir die vorhandenen Tests durchführen, damit wir sicher sind, dass die aktuelle Funktionalität noch korrekt läuft. Dann erweitern wir unsere Methode:
1: public string SimpleTest(int x1, int x2) 2: { 3: if (x1 > x2 * 2) 4: return "x1 > x2 * 2"; 5: if (x1 > x2) 6: return "x1 > x2"; 7: if (x1 < x2) 8: return "x1 < x2"; 9: else 10: return "x1 == x2"; 11: }
Zeile 3+4 haben wir neu hinzugefügt. Nun starten wir eine neue Exploration und PEX ermittelt einen weiteren Test-Case um diese Funktion ebenfalls abzudecken.
Schön - darf's noch ein bisschen mehr sein?
Dieses einfache Sample war ja schon sehr beeindruckend. Die Frage, die sich aber natürlich direkt stellt, ist wie weit geht denn das? Wir wollen nun den Schwierigkeitsgrad für PEX schrittweise steigern. Integer-Werte sind ja noch relativ einfach zu handhaben, aber wie sieht's denn beispielsweise mit Strings aus? Hierzu zunächst wieder eine Methode, die wir testen wollen:
1: public class StringOperations 2: { 3: public string CheckString(string Input) 4: { 5: if (Input.StartsWith("abc") && Input.Length > 10) 6: return Input + " Starts with 'abc' and length > 10"; 7: if (Input.StartsWith("abc")) 8: return Input + " Starts with 'abc'"; 9: if (Input.StartsWith("ABC")) 10: return Input + " Starts with 'ABC'"; 11: return "Unknown pattern"; 12: } 13: }
Stubs erzeugen und Exploration starten. Ob PEX wohl solche Operationen wie "StartsWith" und "Length" versteht?
Es findet tatsächlich alle erforderlichen Input-Parameter und sogar noch mehr! PEX stell fest, dass unsere Methode beim Übergeben einer NULL-Referenz eine Exception wirft. Und damit nicht genug, PEX kann uns auch einen Vorschlag machen, wie wir unseren Code verbessern können. Dazu im "Pex Exploration Results" - Fenster unter Views "Show suggestions window" aufrufen.
Durch einen Doppelklick auf den Eintrag am unteren Rand des Bereichs öffnet sich ein Fenster, das die vorgeschlagene Änderung direkt in unseren Code einfügen kann.
1: public string CheckString(string Input) 2: { 3: // <pex> 4: if (Input == (string)null) 5: throw new ArgumentNullException("Input"); 6: // </pex> 7: if (Input.StartsWith("abc") && Input.Length > 10) 8: return Input + " Starts with 'abc' and length > 10"; 9: if (Input.StartsWith("abc")) 10: return Input + " Starts with 'abc'"; 11: if (Input.StartsWith("ABC")) 12: return Input + " Starts with 'ABC'"; 13: return "Unknown pattern"; 14: }
Die Zeilen 3-6 wurden von PEX erzeugt. Natürlich können wir das entsprechende Verhalten im Code direkt ändern und an unsere Vorstellungen anpassen. Vielleicht ist es aber gar keine schlechte Idee, in diesem Fall eine Exception zu werden. Dies ist das Standard-Verhalten von PEX an dieser Stelle. Wird die erwartete Exception nicht mehr geworfen oder eine andere Exception tritt auf, wird dies durch einen fehlgeschlagenen Test angezeigt.
Der nächste bitte!
So nun wollen wir noch einen Schritt weitergehen und sehen, wie PEX mit Listen umgehen kann. Dazu habe ich folgende Testmethode erstellt (über den Sinn einer solchen Methode wollen wir jetzt nicht nachdenken)
1: int result = 0; 2: if (list.Count > 10) 3: { 4: foreach (int i in list) 5: result += i; 6: } 7: else 8: { 9: foreach (int i in list) 10: result *= i; 11: } 12: return result;
Die Methode bekommt eine Liste von Integer-Werten übergeben. Wenn es mehr als 10 Elemente sind, werden diese addiert, sonst werden die Werte miteinander Multipliziert. Mal sehen, wie PEX mit Listen umgeht.
PEX erkennt noch, dass unsere Methode mit Null-References nicht korrekt umgeht, aber dann verließen sie ihn. Aber freundlicherweise bekommen wir noch einen Hinweis "2 Object Creations". klickt man darauf, dann bekommt man schon mehr Informationen.
Aha, PEX kann also eine List<int> nicht erzeugen. Also was tun? Klickt man den unteren der beiden Einträge an, bietet PEX etwas weiter rechts die Möglichkeit eine Factory zu definieren. Eine Factory ist ein Extensibility-Point mit dem PEX beigebracht werden kann mit solchen Objekten umzugehen. Ein Beispiel für eine solche Factory kann so aussehen:
1: namespace System.Collections.Generic 2: { 3: [PexFactoryClass] 4: public partial class ListFactory 5: { 6: [PexFactoryMethod(typeof(List<int>))] 7: public static List<int> Create(int i) 8: { 9: if (i > 100) 10: i = 100; 11: List<int> l = new List<int>(); 12: for (int j = 0; j < i; j++) 13: { 14: l.Add(j * 10); 15: } 16: return l; 17: } 18: } 19: }
Hier teilt man PEX nun mit, welche Elemente es damit erzeugen kann (Zeile 6). Anschließend implementiert man eine Create-Methode die beliebige Parameter übernehmen kann. In Abhängigkeit dieser Parameter wird nun eine Instanz des gewünschten Objektes erzeugt. In unserem Beispiel übernehmen wir nur einen Parameter der die Länge der Liste angibt. In den Zeilen 9/10 begrenzen wir die Länge der Lsite auf 100 Elemente. Die Liste selbst befüllen wir mit einer Reihe von Zahlen. Hier ist es sicher keine gute Idee, z.B. Zufallszahlen zu verwenden, da diese ja bei jedem Testdurchlauf andere Werte liefern und deshalb der Assert nicht erfolgreich ausgeführt werden kann.
Mit hilfe dieser Factory kannPEX nun unsere Testcases definieren. Dazu ermittelt es einfach geeignete Parameter für die Create-Methode in unserer Factory statt das Objekt selbst zu erzeugen.
Die erzeugten Tests sehen dann so aus:
1: [TestMethod] 2: [PexGeneratedBy(typeof(ListCalculationTest))] 3: public void SumList03() 4: { 5: List<int> list; 6: int i; 7: list = ListFactory.Create(2); 8: ListCalculation listCalculation = new ListCalculation(); 9: i = this.SumList(listCalculation, list); 10: Assert.AreEqual<int>(0, i); 11: } 12: 13: [TestMethod] 14: [PexGeneratedBy(typeof(ListCalculationTest))] 15: public void SumList04() 16: { 17: List<int> list; 18: int i; 19: list = ListFactory.Create(536870912); 20: ListCalculation listCalculation = new ListCalculation(); 21: i = this.SumList(listCalculation, list); 22: Assert.AreEqual<int>(49500, i); 23: }
Nun folgt noch die Kür
Nach den Erfahrungen mit der Liste bereits etwas skeptischer geworden, wollen wir's jetzt aber doch wissen. Wie sieht's mit eigenen Objekten aus? Wie weit kommt PEX damit? Auch hier gibt es wieder eine einfache Methode die wir testen wollen:
1: public class ComplexDataCalculation 2: { 3: public string DoComplexDataCalculation(cData d) 4: { 5: if (!d.IsValid) 6: return "NotValid"; 7: 8: if (d.DataValues.x1 > d.DataValues.x2) 9: return "x1 > x2"; 10: if (d.DataValues.x1 < d.DataValues.x2) 11: return "x1 < x2"; 12: else 13: return "x1 == x2"; 14: 15: } 16: } 17: 18: public class cData 19: { 20: public cDataValues DataValues { get; set; } 21: public string ObsoleteParameter { get; set; } 22: public bool IsValid { get; set; } 23: } 24: 25: public class cDataValues 26: { 27: public int x1 { get; set; } 28: public int x2 { get; set; } 29: }
Die Methode bekommt einen komplexen Datentyp übergeben. Und was macht PEX???
PEX erkennt nicht nur, dass wir zwei Null-Exceptions abfangen sollten, sondern kann auch unser Datenobjekt so initialisieren, dass wir wieder eine 100% Codeabdeckung bekommen. Die Unit-Tests sehen ungefähr so aus:
1: [TestMethod] 2: [PexGeneratedBy(typeof(ComplexDataCalculationTest))] 3: public void DoComplexDataCalculation04() 4: { 5: cDataValues cDataValues; 6: cData cData; 7: string s; 8: cDataValues = new cDataValues(); 9: cDataValues.x1 = 3; 10: cDataValues.x2 = 4; 11: cData = new cData(); 12: cData.DataValues = cDataValues; 13: cData.ObsoleteParameter = ""; 14: cData.IsValid = true; 15: ComplexDataCalculation complexDataCalculation = new ComplexDataCalculation(); 16: s = this.DoComplexDataCalculation(complexDataCalculation, cData); 17: Assert.AreEqual<string>("x1 < x2", s); 18: }
Das ist schon extrem beeindruckend, wie PEX tatsächlich eine entsprechende Instanz unseres Datenobjektes erzeugt und initialisiert und das so, dass wir alle Testcases abdecken. Wirklich beeindruckend.
Was haltet ihr davon? Würde mich über Feedback freuen.
Die Integration des TFS mit Visual Studio ist eine richtig schöne Sache. Eine Stelle an der die Vorteile dieser Integration schön sichtbar werden ist die Erzeugung einen Workitems direkt aus einem Test-Result heraus. Wenn also z.B. ein Test fehlgeschlagen ist, kann daraus direkt ein Bug-Workitem erzeugt werden. Der Clou dabei ist, dass das Test-Result automatisch auf dem TFS veröffentlicht und als Attachment an das Workitem angehängt wird. Damit hat der Entwickler der den Bug beheben soll Zugriff auf den durchgeführten Test und die Results. Dies funktioniert mit allen Testarten sofern der Entwickler mit seiner Visual Studio Edition die entsprechenden Testarten ausführen kann. Somit kann der Entwickler z.B. bei einem Unit-Test diesen verwenden um den Testcase einfach zu debuggen. Und bei manuellen Tests stellt die Testspezifikation die Beschreibung der Repro-Steps dar. Auf jeden Fall ein Zeitgewinn. Man kann aber beispielsweise damit auch Aufgaben definieren, dass ein bestimmter Test noch mit zusätzlichen Test-Cases angereichert werden soll etc. Dazu geht man einfach mit der rechten Maustaste auf den entsprechenden Eintrag im Testresults-Fenster und wählt aus dem Kontext-Menü den entsprechenden Workitemtyp aus. Wird statt der Liste der Workitems "No Active Team Project" angezeigt, dann gibt es hier eine einfache Lösung, die aber nicht ganz intuitiv ist. 1.) Sicherstellen dass im Team-Explorer das gewünschte Projekt angezeigt wird in dem man das neue Workitem anlegen möchte. 2.) Dieses Team-Projekt aktiv markieren (das Projekt wird fett dargestellt) Nun werden die WorkitemTypen die im ProcessTemplate dieses Projektes definiert sind zur Auswahl angezeigt. Das Projekt selbst muss nicht unbedingt in der Quellcode-Verwaltung des TFS abgelegt sein.
 Nächste Woche Dienstag bin ich mit zwei Vorträgen auf der ADC08 vertreten. Testing Practices mit VSTS und TFS VSTS bringt eine ganze Reihe von Testmethoden. Insbesondere die Edition für Tester bietet verschiedene Testarten. Die Implementierung der unterschiedlichen Testarten ist inzwischen hinlänglich beschrieben. Wie diese Tests in Real-World-Projekte eingesetzt werden, um tatsächlich die Qualität zu verbessern, beschreibt der Vortrag ebenso wie die Lösung von Real-World-Problemen. Dabei werden Themen wie die Bereitstellung von Testumgebungen, Testplanung und Testdurchführung sowie Testdokumentation ebenso beleuchtet wie die Frage, in welchen Fällen eine Edition für Tester notwendig ist, wo es mögliche Alternativen gibt und wie verschiedene Akteure innerhalb des Projekts wie z.B. Fachabteilungen eingebunden werden. UI-Testing mit UI Automation Unit-Testing und Web-Testing verbreiten sich mit VSTS und anderen Testing-Tools immer mehr. Was diese Testmethoden jedoch nicht abdecken, ist quasi die „letzte Meile“, die Oberfläche der Anwendungen. Um diese in Tests einzubinden sind entweder teure Tools erforderlich, oder man nutzt das weitgehend unbekannte UI Automation Framework, das Bestandteil des .NET 3.0 Frameworks ist. Der Vortrag erläutert zunächst, wie man mit Hilfe des UI Automation Frameworks Windows- und Web-Anwendungen kontrollieren kann. Anschließend werden diese Methoden in Unit-Tests integriert, um damit automatisierte UI-Tests aufzubauen. Als krönender Abschluss wird ein UI-Test-Rekorder implementiert, mit dem UI-Aktionen aufgezeichnet und automatisiert in Unit-Test überführt werden können. Der Vortrag beschreibt neben den Möglichkeiten auch Grenzen des UI Automation Frameworks und mögliche Lösungen.
 Seit ein paar Tagen ist ein neuer Web-Cast online in dem ich zusammen mit Christian Binder zusammen erörtere welche Vorteile die hierarchische Organisation von Workitems bietet. Ohne schon zuviel vom Inhalt verraten zu wolle, es geht um Requirementmanagement, Traceability, Impace-Analyse und einiges mehr. Im Webcast wird ein kostenloses Tool vorgestellt mit dem bereits mit TFS 2008 hierarchische Workitems realisiert werden können.
Mit Hilfe des UI Automation Frameworks (UIA) können Oberflächen aus einer Testanwendung heraus "ferngesteuert" werden. Damit lassen sich z.B. UI-Tests bauen. Die Grundlagen hierzu habe ich in zwei Blogposts bzw. Webcasts beschrieben. MSDN WebCast zum UI-Recording MSDN WebCast zum UI-Testing mit dem UI Automation Framework Wenn man sich mit dieser Technologie etwas intensiver beschäftigt wird man früher oder später auf ein paar Probleme stoßen. So veröffentlichen beispielsweise nicht alle Third-Party-Controls alle erforderlichen Funktionalitäten über die UIAutomation Patterns. Und leider gibt es auch bei Standard-Winforms-Controls noch ein paar Lücken. Ein Beispiel hierzu ist das MenuStrip-Control. Dieses Control bietet leider nicht die erforderlichen Events um die Auswahl eines Menüeintrags aufzuzeichnen. Und für die Auswahl eines Menüeintrages gibt es auch kein geeignetes Invoke-Pattern o.ä. Das schöne am UI Automation Framework ist jedoch, dass man diese Funktionalitäten selber nachrüsten kann. Dies wollen wir nun am Beispiel des MenuStrips mal durchspielen. Zum Einsatz kommen sog. Serverside Provider. Wir gehen zunächst her und erstellen uns ein eigenes Control das wir von MenuStrip und entsprechenden Interfaces aus dem UIA ableiten. public class ExtendedMenuStrip : MenuStrip, IRawElementProviderSimple, IValueProvider
Über das Interface IValueProvider geben wir an, dass das Control das ValuePattern implementieren soll. Wir verwenden hier das ValuePattern statt des InvokePatterns da wir ja angeben müssen, welches Menüelement aufgerufen werden soll.
Zunächst werden wir das Interface IRawElementProviderSimple implementieren.
1: #region IRawElementProviderSimple Members 2: public object GetPatternProvider(int patternId) 3: { 4: if (patternId == ValuePatternIdentifiers.Pattern.Id) 5: { 6: return this; 7: } 8: else 9: { 10: return null; 11: } 12: } 13: 14: /// <summary> 15: /// Get the value of properties 16: /// </summary> 17: /// <param name="propertyId"></param> 18: /// <returns></returns> 19: public object GetPropertyValue(int propertyId) 20: { 21: if (propertyId == AutomationElementIdentifiers.ClassNameProperty.Id) 22: { 23: return "ExtendedMenuStrip"; 24: } 25: else if (propertyId == AutomationElementIdentifiers.ControlTypeProperty.Id) 26: { 27: return ControlType.MenuBar.Id; 28: } 29: 30: if (propertyId == AutomationElementIdentifiers.HelpTextProperty.Id) 31: { 32: return "Help for ExtendedMenuStrip"; 33: } 34: 35: if (propertyId == AutomationElementIdentifiers.AutomationIdProperty.Id) 36: { 37: return this.Name; 38: } 39: 40: if (propertyId == AutomationElementIdentifiers.IsEnabledProperty.Id) 41: { 42: return true; 43: } 44: 45: if (propertyId == AutomationElementIdentifiers.ItemStatusProperty.Id) 46: { 47: return SelectedItemID; 48: } 49: 50: else 51: { 52: return null; 53: } 54: } 55: 56: /// <summary> 57: /// Get the host rawelement provider 58: /// </summary> 59: public IRawElementProviderSimple HostRawElementProvider 60: { 61: get 62: { 63: return AutomationInteropProvider.HostProviderFromHandle(Handle); 64: } 65: } 66: 67: /// <summary> 68: /// Get the provider options 69: /// </summary> 70: public ProviderOptions ProviderOptions 71: { 72: get 73: { 74: return ProviderOptions.ServerSideProvider; 75: } 76: } 77: 78: #endregion
Die Methode GetPatternProvider gibt das Objekt selbst zurück, wenn ein Provider für ein ValuePattern angefordert wird. Da unser Control nur dieses Pattern implementiert, reagiert die Funktion nur auf dieses Pattern. Wir können das Control selbst zurückgeben, da dieses ja das ValuePattern implementiert. Altzernativ könnte man natürlich auch einen expliziten Provider definieren und hier zurückgeben. Die Methode GetPropertyValue gibt je nach übergebenen PropertyID einen entsprechenden Wert zurück. Hier wird z.B. die ID des Controls als AutomationID zurückgegeben. Die beiden Properties HostRawElementProvider und ProviderOptions sind readonly und geben einen Hostprovider bzw. den Typ der Providers zurück.
Die Implementierung des IValueProvider Interface ist ebenfalls recht einfach:
1: #region IValueProvider Members 2: /// <summary> 3: /// Get readonly as false 4: /// </summary> 5: public bool IsReadOnly 6: { 7: get 8: { 9: return false; 10: } 11: } 12: 13: /// <summary> 14: /// Set value: Invoke the click event of the item 15: /// </summary> 16: /// <param name="value"></param> 17: public void SetValue(string value) 18: { 19: object[] param = new object[1]; 20: param[0] = null; 21: ToolStripMenuItem toolStripMenuItem = getToolStripMenuItemByName(this.Items, value); 22: if (toolStripMenuItem != null) 23: toolStripMenuItem.GetType().GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(toolStripMenuItem, param); 24: } 25: 26: /// <summary> 27: /// Get the ID of the selected item 28: /// </summary> 29: public string Value 30: { 31: get 32: { 33: return SelectedItemID; 34: } 35: } 36: #endregion
Entscheidend ist hier die Methode SetValue. Hier ermitteln wir das entsprechende Element innerhalb des MenuStrips (ToolStripMenuItem) und rufen hier einen Click-Event auf. Da die OnClick Methode nicht public ist, müssen wir hier Reflection verwenden um diese aufrufen zu können (siehe auch Events von WinForms Controls von Außen aufrufen). Das Aufrufen des Events ist an dieser Stelle notwendig, da ja mehrere Eventhandler registriert sein können und die wollen wir alle aufrufen. Durch den Click-Event verhält sich das Control am ähnlichsten zum Anklicken in der UI.
Nun brauchen wir noch einen Event der ausgelöst wird wenn ein Menüeintrag ausgewählt wird.
1: /// <summary> 2: /// Set eventhandlers 3: /// </summary> 4: /// <param name="items"></param> 5: public void SetExtendedMenuStripEventHandlers(ToolStripItemCollection items) 6: { 7: for (int i = 0; i <= items.Count - 1; i++) 8: { 9: ToolStripMenuItem toolStripMenuItem = items[i] as ToolStripMenuItem; 10: if(toolStripMenuItem != null) 11: { 12: toolStripMenuItem.Click += new EventHandler(ItemRaiseAutomationEvent); 13: SetExtendedMenuStripEventHandlers(toolStripMenuItem.DropDownItems); 14: } 15: } 16: } 17: 18: /// <summary> 19: /// Raise automation event 20: /// </summary> 21: /// <param name="sender"></param> 22: /// <param name="e"></param> 23: private void ItemRaiseAutomationEvent(object sender, EventArgs e) 24: { 25: if ((AutomationInteropProvider.ClientsAreListening)) 26: { 27: AutomationEventArgs args = new AutomationEventArgs(InvokePatternIdentifiers.InvokedEvent); 28: this.SelectedItemID =((ToolStripMenuItem)sender).Name; 29: AutomationInteropProvider.RaiseAutomationEvent(InvokePatternIdentifiers.InvokedEvent, this, args); 30: } 31: }
Die Methode SetExtendedMenuStripEventHandlers registriert auf jedem ToolStripMenuItem einen EventHandler. Dieser löst dann den AutomationEvent aus. Hier übergeben wir im Feld SelectedItemID den Name des ToolStripMenuItems das angeklickt wurde.
Nun müssen wir noch die Methode wndProc überschreiben damit diese bei WM_GETOBJECT den entsprechenden AutomationProvider zurückgibt.
1: /// <summary> 2: /// Process Windows-based messages 3: /// </summary> 4: /// <param name="m"></param> 5: [PermissionSetAttribute(SecurityAction.Demand, Unrestricted = true)] 6: protected override void WndProc(ref Message m) 7: { 8: // 0x3D == WM_GETOBJECT 9: Int32 param = 0; 10: if (Int32.TryParse(m.LParam.ToString(), out param)) 11: { 12: if ((m.Msg == 0x3D) && (param == AutomationInteropProvider.RootObjectId)) 13: { 14: m.Result = AutomationInteropProvider.ReturnRawElementProvider( 15: Handle, m.WParam, m.LParam, (IRawElementProviderSimple)this); 16: return; 17: } 18: } 19: base.WndProc(ref m); 20: }
Das so erstellte Control kann nun statt des normalen MenuStrip Controls verwendet werden und ist nun über UI Automation ansprechbar. Die fertige Solution inkl. dem UI-Recoder kann hier heruntergeladen werden:
Vielleicht noch kurz eine Anmerkung weshalb der Zugriff auf die ToolStripItems etwas umständlich gelöst wurde. Eigentlich wäre es doch einfach der direkt auf dem ToolStripMenuItem den Event auszulösen. Dann könnte der Recoder auch direkt einen Invoke auf dem ToolStripMenuItem generieren. Dazu müsste dann aber der ToolStripMenuItem abgeleitet werden und dann wird's aber mit der Designer-Unterstützung problematisch. Denn um das Control soweit umzubauen, dass im Designer beim Hinzufügen von ToolStripMenuItems zum MenuStrip der abgeleitete Typ verwendet wird ist ein deutlich höherer Aufwand notwendig als das Ganze über den MenuStrip laufen zu lassen.
 Das MSBuild Extension Pack bietet eine Sammlung von BuildTasks für MSBuild und damit natürlich auch TeamBuild die kostenlos von CodePlex heruntergeladen werden können. Diese BuildTasks bieten verschiedene Operationen im Rahmen eines Builds wie z.B. das Zippen und Vermailen von Dateien, Prüfen des Buildprojektes mit FxCop oder StyleCop, verschiedene Dateioperationen und vieles mehr. Die Bibliothek ist gut strukturirert und dokumentiert. MSBuild Extension Pack - Home
Möchte man einen Event eines Controls per Code auslösen und somit alle registrierten Delegates aufrufen, wie es beim eigentlichen Auslösen des Events passiert, dann kann dieses Beispiel helfen. Jedes Control besitzt für seine einzelnen Events eine Methode den event auszulösen, z.B. OnClick(EventArgs e). Die Methoden sind allerdings private und können damit von außerhalb des Controls nicht so einfach aufgerufen werden. Bei einem einfachen Control wie z.B. einem Button geht das einfach durch Ableitung: 1: public partial class CustomButton : Button 2: { 3: public CustomButton() 4: { 5: InitializeComponent(); 6: } 7: 8: public void RaiseClickEvent(EventArgs e) 9: { 10: base.OnClick(e); 11: } 12: }
Etwas schwieriger wird es bei komplexeren Controls, z.B. einem MenuStrip. Möchte man den Click-Event eines ToolStripMenuItem aufrufen, müsste man ja das ToolStripMenuItem ableiten, was aber zur Folge hätte, dass das komplette MenuStrip-Control umbauen muss. Hier kann man mit Hilfe von Reflection eine bessere Lösung implementieren. Bei dieser Lösung wird nur das MenuStrip abgeleitet und um eine RaiseClickEvent-Methode erweitert der als Parameter ein ToolStripItem entgegen nimmt. Auf diesem wird dann per Reflection die Private-Methode OnClick aufgerufen.
1: public partial class CustomMenuStrip : MenuStrip 2: { 3: public CustomMenuStrip() 4: { 5: } 6: 7: public void RaiseClickEvent(ToolStripItem m) 8: { 9: Type t = m.GetType(); 10: object[] para = new object[1]; 11: para[0] = null; 12: t.GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(m, para); 13: } 14: }
Ich hatte gerade das Problem, dass in einem Feld in der Datenbank Einträge wie z.B. "Thomas, Schissler" standen und ich die in "Schissler, Thomas" ändern wollte. Hier hilft folgendes kleines Skript: select CASE LEN(ResponsibleName)
WHEN 0 THEN ResponsibleName
ELSE SUBSTRING(ResponsibleName, charindex ( ',', ResponsibleName )+2, len(ResponsibleName))
+ ', '
+ SUBSTRING(ResponsibleName, 1, charindex ( ',', ResponsibleName )-1)
END
from data
In einem früheren Beitrag habe ich beschrieben, wie man kleinere Listen mit LINQ effizien speichern kann. Hierzu verwende ich einfach ein XML-Feld in der entsprechenden Tabelle und lege die Liste dann dort als XML-Serialisierung ab. Nun stand ich vor der Herausforderung, dass ich direkt auf der Datenbank dieses Feld abfragen wollte. Glücklicherweise beitet T-SQL eine sehr gute XML-Unterstützung, unglücklicherweise gibt es eine vielzahl von Techniken dies zu tun und die Treffer meiner Internetrecherche waren sehr unübersichtlich. Deshalb hier nochmals kurz zusammengefasst, wie ich das gelöst habe. Ich habe in einem Feld folgenden XML-Inhalt der ein Dictionary mit 5 Einträgen repräsentiert: <Root>
<item>
<key>
<int>1</int>
</key>
<value>
<decimal>17.00</decimal>
</value>
</item>
<item>
<key>
<int>2</int>
</key>
<value>
<decimal>17.81</decimal>
</value>
</item>
<item>
<key>
<int>3</int>
</key>
<value>
<decimal>18.62</decimal>
</value>
</item>
<item>
<key>
<int>4</int>
</key>
<value>
<decimal>19.43</decimal>
</value>
</item>
<item>
<key>
<int>5</int>
</key>
<value>
<decimal>20.24</decimal>
</value>
</item>
</Root>
Die Struktur der XML-Daten ist bei allen Datensätzen gleich. Nun wollte ich diese Werte in 5 separaten Spalten ausgeben um diese einfachin Excel weiterverarbeiten zu können. Das macht folgendes Skript:
SELECT PackSIzeID, Units,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear1,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear2,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear3,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear4,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear5
FROM data_PackSizes
CROSS APPLY Units.nodes('//Root/item[1]/value') u1(l)
CROSS APPLY Units.nodes('//Root/item[2]/value') u2(l)
CROSS APPLY Units.nodes('//Root/item[3]/value') u3(l)
CROSS APPLY Units.nodes('//Root/item[4]/value') u4(l)
CROSS APPLY Units.nodes('//Root/item[5]/value') u5(l)
Hier kann ich die 5 values als separate Nodes adressieren und dann in der Feldliste entsprechend auswählen. Das Ergebnis sieht dann so aus:
Vielleicht geht das auch noch eleganter, aber für mich hat's erst mal funktioniert und deshalb habe ich hier erst mal nicht mehr Zeit investiert.
Weitere Infos zum Thema: SQL XML-Workshop von Jacob Sebastian
Technet-Whitepapaer: XML Best Practices for Microsoft SQL Server 2005
Die nächste Version der TFS Power-Tools werden ein paar richtig coole Features enthalten sein. Z.B. ein neuer Knoten "Team Members" im Team Explorer über den man mit allen Team-Mitglieder kommunizieren kann und worüber man auch z.B. schnell die Pending Changes oder die Shelfsets einzelner Mitglieder findet etc.   Zusätzlich lassen sich damit Komponenten wie z.B. Checkin-Policies oder Workitem-Controls einfach distributieren.  Und von vielen heiß ersehnt, es gibt jetzt eine Windows Explorer Integration zur Quellcode-verwaltung.   Darüber hinaus ist noch der Power-Shell Support Bestandteil der neuen Power-Tools Weitere Details unter Brian Harrys Blog bharry's WebLog : Preview of the next TFS Power Tools release
 Ok, OK, ich weiß, ich bin spät dran, aber ich möchte dennoch nicht versäumen, einen kurzen Rückblick auf den Herbstcampus zu tun und meine Folien zu veröffentlichen. Interessant war für mich an der Veranstaltung, dass es Tracks sowohl für JAVA als auch .Net gab. Ich selbst hatte zwei Talks: Qualitätsmanagement mit VSTS und TFS In dieser Session habe ich zunächst einmal beleuchtet, warum Entwickler QM nicht unbedingt mögen. Einer der Gründe liegt in der mangelnden Integration von QM in den Entwicklungsprozess. Gerade hier bietet VSTS und TFS einige Verbesserungen. Wichtig ist, dass QM nicht erst mit dem Testing beginnt, sondern bereits früh im Prozess ansetzen muss. Ohne ein gutes Requirement-Management wird kein gutes Qualitäts-Management möglich sein. Im Vortrag habe ich demonstriert, welche Methoden mit diesem Toolset über die verschiedenen Prozessphasen zur Verfügung stehen um in Software-Projekten wirklich mehr Qualität zu erzielen. Agile Development Process - Ein Architektur-basierter Entwicklungsprozess Architektur und Prozesse werden meist getrennt betrachtet. Dass aber gerade eine gemeinsame Betrachtung dieser beiden Themen viele Vorteile bringt, habe ich versucht in dieser Session zu vermitteln. Im Kern ging es darum, dass verschiedene Prozesse wie z.B. das UI Driven Development erst durch eine passende Architektur ermöglicht wird. Sehr gut fand ich auch die Diskussion am Ende meines Vortrags. Das versprochene Whitepaper zu diesem Vortrag wird noch nachgereicht.
SharePoint veröffentlicht die Dokumentbibliotheken per WebDAV, d.h. man kann über \\<Servername>\sites\<ProjektName> beispielsweise auf die Dokumente eines TFS-Projektes zugreifen. Das funktioniert standardmäßig aber nicht von einem Windows 2003 Server aus. Hier muss der WebDAV Client zuerst aktiviert werden. Hierzu muss der Dienst "WebClient" gestartet werden. 
Ab dem 01.10.2008 werden Besitzer einer Visual Studio 2008 Team System Development Edition auch eine Visual Studio 2008 Team System Database Edition erhalten und umgekehrt. In Visual Studio 2010 werden diese beiden Produkte wohl zu einem verschmolzen. Weitere Informationen unter Visual Studio 2010 and .NET Framework 4.0 Overview im Kapitel "Better Together – Visual Studio Team System Development Edition and Database Edition"
Am 08.10.2008 haben wir Stefan Lieser zu Gast bei der .Net Developer-Group Ulm. Er wird in seinem Vortrag einige "Software Design Principles" vorstellen und erläutern wie diese helfen, Software wartbarer wird. Mitglieder und Gäste sind herzlich eingeladen. Weitere Infos unter http://www.dotnet-ulm.de/Treffen.aspx
Eine neue User-Group die sich speziell mit Team System beschäftigt wurde vor kurzem gegründet. Dabei handelt es sich um eine virtuelle usergroup, das heißt die Treffen finden in Second Life und über Office Live Meeting statt. Ich bin schon mal gespannt auf das nächste Treffen. Team System User Group - Virtual Edition
In inzwischen über 47 Videos werden in dieser Serie HowTos rund um das Thema Visual Studio Team System präsentiert. Kurz und verständlich bekommt man hier viele BestPractices und Tips. "How Do I?" Videos for Team System
Es ist wohl noch eine weile hin, bis wir Rosario wirklich nutzen dürfen. Brian Harry hat aber schon mal vorab veröffentlicht, welche Systemvoraussetzungen und Abhängigkeiten Rosario haben wird. So werden wohl unter anderem auch SQL 2005 und Office 2003 nicht mehr unterstützt. Dies gibt jetzt bereits die Möglichkeit, rechtzeitig zu planen und sich auf die Anforderungen ggf. entsprechend vorzubereiten. bharry's WebLog : Charting a course for TFS "Rosario"
Der Team Foundation Server bietet die flexible Möglichkeit ProcessTemplates individuell anzupassen. Diese ProcessTemplates enthalten die Definition der Workitemtypes (welche gibt es und welche Felder haben diese), die Workflows (was passiert wenn ich bei einem bestimmten Workitem eine bestimmte Aktion auslöse), und vieles mehr wie Standarddokumente etc. Dieses ProcessTemplate kann man nicht nur im Vorfeld definieren, sondern auch für laufende Projekte noch anpassen, was in der Praxis eine enorme Hilfe ist. Wie's genau geht beschreibt Christian Binder in einem zweiteiligen Blog-Beitrag. Teil 1 Teil 2
Richard Hundhausen hat eine Liste mit Tools und nützlichen Helferlein rund um Team Foundation Server veröffentlicht. Team System Widgets
am 08.09.2008 findet bei der .Net Developergroup Ulm ein 'Cool Tipps' Wettbewerb statt. Idee hinter diesem Wettbrewerb ist, einen stärkeren Austausch innerhalb der Community zu erreichen. Mit diesem besonderen Event wollen wir auch das 2-jähriges Bestehen unserer Usergroup und hoffentlich auch das 200. Mitglied feiern. Jeder Entwickler hat seine kleinen Tricks um bestimmte Aufgaben schnell, effizient und elegant zu erledigen. Unser Ziel ist ein Austausch dieses Wissens. Aus diesem Grunde wollen wir am 08. September einen ganz besonderen Wettbewerb veranstalten. Die Mitglieder der .net Developergroup Ulm sind aufgerufen, ihr Knoff-Hoff in einer Kurzpräsentation vorzustellen. Das vorgestellte Thema kann aus einem weiten Bereich gewählt werden. Egal ob es sich um ein Code-Snippet handelt, um ein Tool, eine spezielle Methode oder ein Designpattern. Alles was mit der .Net Programmierung zu tun hat ist von Interesse. Und jeder Teilnehmer kann wertvolle Sachpreise gewinnen. Mitmachen lohnt sich! Hier die Rahmenbedingungen für den Wettbewerb: - Teilnahmeberechtigt sind alle Mitglieder der .net Developergroup Ulm
- Jeder Teilnehmer erhält 10 Min. für seinen Beitrag
- Alle Beiträge müssen in einem Zusammenhang mit der Programmierung unter .Net stehen.
- Die Besucher der Veranstaltung wählen am Ende die besten Beiträge, die mit wertvollen Sachpreisen belohnt werden.
- Themenvorschläge sind bis spätestens 31.08. per E-Mail einzureichen unter info@dotnet-ulm.de
Sachpreise: - 1 Enterprise Studio-Lizenz (Wert 1100$) von
| | - 2 RadControl-Lizenzen (Wert je 1299$) von
| | - 1 ReSharper-Lizenz (Wert 140€) von
| | - 3 Jahres Abos (Wert je 76,50€)von
| | - 5 Buchgutscheine (a 60 €) von
| | Bereits angemeldet Themen: - Lokalisiertes Property-Grid
- Vista Gadgets programmieren
- Broadcast Messages mit Controls
- Zeitspar-Tools für TFS
- Object Cloner
- Data Sets per WCF übertragen
- PDF- und Excel-Export aus ASP.Net mit Bordmitteln
- Generische Fehlerklasse
- Beliebige Datenformate per Serialisierung erzeugen und lesen
Wer noch Interesse hat, am Wettbewerb teilzunehmen, kann gerne noch einen Vortrag an info@dotnet-ulm.de einrichen. Und natürlich sind alle interessierten gerne als Zuhörer willkommen. Und vielleicht schaffen wir es ja doch noch bis zum 08.09 die fehlenden 7 Mitglieder zu gewinnen, um die 200 voll zumachen.
Bei der Neuinstallation eines Entwicklungsrechners dauert es immer ewig, bis man sich die ganzen nützlichen Helferlein zusammengesucht hat, die man im Laufe der Zeit zu schätzen gelernt hat. Deshalb habe ich mir gedacht, ich schreibe mir mal eine Liste, die ich dann immer wieder ergänzen kann. Und vielleicht ist für den einen oder anderen da auch noch was interessantes dabei. Also so könnte ein Entwicklungsrechner aussehen:
Betriebsystem / Standardanwendungen:
- Windows Vista Ultimate
- Office 2007
- SQL-Server 2005 Express
- SQL-Server 2005 Management Studio
Entwicklungsumgebung:
Tools
Stand 30.10.2008 To be continued...
Über das Erscheinen des .Net Framework 3.5 SP1 haben ja bereits genügen Leute berichtet, da muss ich jetzt nicht noch einen draufsetzen. Wer möchte, kann sich den recht ausführlichen Blog-Beitrag von Dariusz anschauen. Ich habe natürlich auch sofort das SP installiert. Die letzten 3 Std. habe ich damit zugebrach einen Fehler zu finden. Und was soll ich sagen, das Problem liegt am SP. Folgende Situation. Ich arbeite an einem Projekt, das intensiv ASP.Net AJAX nutzt. Dort habe ich an verschiedenen Stellen die Übergabe von Daten aus dem CodeBehind an Javascript. Diese löse ich, indem ich im Code behind folgenden Code verwende: ScriptManager scriptManager = ScriptManager.GetCurrent(Page);
scriptManager.RegisterDataItem(this, "StringToTransfer");
In Javascript kann ich dann auf diese Werte zugreifen:
function EndRequestHandler(sender, args) {
if (sender._dataItems != null) {
if (sender._dataItems.__Page != null) {
if (sender._dataItems.__Page == 'StringToTransfer') {
fnShowSizedPopup('../../Web/Search/CopyProducts.aspx', 500, 400);
}
}
}
}
Das hat bisher problemlos funktioniert. Nach der Installation des SP1 war allerdings sender._dataItems immer null. Nachdem ich das SP1 deinstalliert habe, funktioniert es wieder wunderbar. Na ich werde jetzt wohl erst mal ohne SP1 leben und mir bei Gelegenheit mal anschauen, wie ich das Problem umgehe. Oder hat vielleicht jemand eine Idee, woran das liegen könnte?
Nachtrag:
Dank Hannes habe ich eine Lösung gefunden. Im obigen Beispiel muss man sender._dataItems mit args.get_dataItems() ersetzen, dann klappt's auch mit dem SP1
 Zusammen mit Christian Binder habe ich nun einen MSDN Webcast aufgenommen der sich mit dem Thema UI Events und Record & Play für UI Testing beschäftigt. Dieser Webcast ist als Fortsetzung zum Thema UI Testing mit dem UI Automation Framework aufgebaut. Der Webcast selbst wird als Download ab dem 08.08.08 (cooles Datum) verfügbar sein. Den Demo_Code zum Webcast kann man ab sofort hier runterladen. Kurz hier der Inhalt des Webcasts zusammengefasst. Über das UI Automation Framework kann man Events aus einer Anwendung abfangen. Diese Events kann man zunächst am besten mit dem UISpy untersuchen. Nun kann man einen kleinen Recorder erstellen, der diese Events nutzt, um Benutzereingaben in einer Anwendung zu erkennen und automatisiert Code erstellt, der diese Benutzereingaben simuliert. Dieser Code kann nun in einem Unit-Test genutzt werden um automatisiert im Rahmen eines Testdurchlaufes die Benutzerinteraktion zu wiederholen. Der Clou dabei ist, dass sogar die Asserts für die erwarteten Ergebnisse automatisiert aufgezeichnet werden können. Download Demo-Code Download Webcast
Ich bin gerade dabei, für den Herbst meine Vorträge zu koordinieren. Ich werde von September bis Dezember viel unterwegs sein. Nun habe ich mal die ganzen aktuellen Vortragsthemen gesammelt, um hier einen kleinen Überblick zu geben. Wer Interesse hat, einen dieser Vorträge zu hören, ich werde in Kürze die Termine veröffentlichen, an denen ich die jeweiligen Vorträge halten werde. Möchte mich jemand für einen Vortrag buchen, einfach eine kurze Mail an mich. Für INETA User-Groups besteht auch die Möglichkeit, mich über das deutsche Speaker-Bureau zu buchen. Sollte sonst jemand Interesse an einem Vortrag zu den Themengebieten VSTS und Team Foundation Server, Software-Architektur, Entwicklungsprozesse oder Qualitätsmanagement haben, ich bin gerne bereit, mein Angebot entsprechend zu erweitern. | Qualitätsmanagement mit VSTS und TFS | Qualität spielt bei Software eine immer stärkere Rolle. Gleichzeitig werden immer effizientere Entwicklungsprozesse angestrebt. Dies lässt sich nur mit geeigneter Tool-Unterstützung und passenden Lösungen zu Prozessen und Software-Architektur erzielen. Mit Visual Studio Team System und Team Foundation Server stehen Tools zur Verfügung, die nicht nur eine entsprechende Testunterstützung bietet, sondern auch komplette Qualitätsprozesse unterstützt. Der Vortrag zeigt, wie Qualitätsprozesse durch TFS unterstützt werden. Anschließend werden verschiedene Testmethoden vorgestellt und einige Praxis-Tipp für deren Einsatz gegeben. | | Agile Development Process - Ein Architekturbasierter Entwicklungsprozess | Moderne Software-Anwendungen werden immer komplexer. Dadurch gewinnt auch die Software-Architektur immer mehr an Bedeutung. Wartbarkeit, Testbarkeit, Erweiterbarkeit und Teamentwicklung sind nur einige Aspekte, die eine gute Architektur unterstützen soll. Doch diese Aspekte können nicht durch ein einzelnes Architekturkonzept abgedeckt werden. Dieser Vortrag stellt verschiedene Architektur-Patterns wie Komponentenorientierung, Contract First Design, Service-Orientierung und UI Driven Development vor. Und vor allem wird gezeigt, wie diese Konzepte zu einem praxiserprobten Entwicklungsprozess verbunden werden können. | | Mehrschichtige Architekturen mit .Net | Mehrschichtige Architekturen sind heute eigentlich oft Standard, vor allem bei verteilten Anwendungen. Allerdings wird diese Architektur oftmals zu sehr an technischen Belangen ausgerichtet. Die Session zeigt, wie man mehrschichtige Architekturen plant und diese flexibel und leitungsfähig aufbaut. Es werden verschiedene praxiserprobte Patterns vorgestellt. | | Build-Management mit Team Foundation Server | Mit Team Foundation Server steht ein leistungsfähiges integriertes Buildsystem zur Verfügung. Wie man dieses im Rahmen der Projekte nutzt und welche Vorteile sich daraus ergeen zeigt diese Session. Darüber hinaus wird der Einsatz verschiedener Buildsteps zum Deployment, Versionierung etc. vorgestellt. | | Testing Practices mit VSTS und TFS | VSTS bringt eine ganze Reihe von Testmethoden. Insbesondere die Edition für Tester bietet verschiedene Testarten. Die Implementierung der unterschiedlichen Testarten ist inzwischen hinlänglich beschrieben. Wie diese Tests in Real-World-Projekte eingesetzt werden, um tatsächlich die Qualität zu verbessern, beschreibt der Vortrag ebenso wie die Lösung von Real-World-Problemen. Dabei werden Themen wie die Bereitstellung von Testumgebungen, Testplanung und Testdurchführung sowie Testdokumentation ebenso beleuchtet wie die Frage, in welchen Fällen eine Edition für Tester notwendig ist, wo es mögliche Alternativen gibt und wie verschiedene Akteure innerhalb des Projekts wie z.B. Fachabteilungen eingebunden werden. | | UI-Testing mit UI Automation | Unit-Testing und Web-Testing verbreiten sich mit VSTS und anderen Testing-Tools immer mehr. Was diese Testmethoden jedoch nicht abdecken, ist quasi die „letzte Meile“, die Oberfläche der Anwendungen. Um diese in Tests einzubinden sind entweder teure Tools erforderlich, oder man nutzt das weitgehend unbekannte UI Automation Framework, das Bestandteil des .NET 3.0 Frameworks ist. Der Vortrag erläutert zunächst, wie man mit Hilfe des UI Automation Frameworks Windows- und WPF-Anwendungen kontrollieren kann. Anschließend werden diese Methoden in Unit-Tests integriert, um damit automatisierte UI-Tests aufzubauen. Als krönender Abschluss wird ein UI-Test-Recorder implementiert, mit dem UI-Aktionen aufgezeichnet und automatisiert in Unit-Test überführt werden können. Der Vortrag beschreibt neben den Möglichkeiten auch Grenzen des UI Automation Frameworks und mögliche Lösungen. | | Closing Tool-Gaps in your Development Process with the TFS API | The efficiency of development processes is based on a powerful and integrated tool support. But development processes are individual and no standard software can fulfill this integration 100%. With the Team Foundation Server API we have a powerful technology to extend the standard functionality for our needs. As an example in this session we will live code a tool to organize workitems in a hierarchical way and you will learn how this can improve your development process. Also you will get some additional visions about how you can use TFS Extensibility to make real cool things with your TFS. | | Durchgängige Entwicklungsprozesse mit Visual Studio Team System | Mit Visual Studio Team System bietet Microsoft eine leistungsfähige Entwicklungsplattform die den gesamten Lebenszyklus eines Entwicklungsprojektes vom Requirement Management bis zum Systembetrieb abbilden kann. Der Vorteil dabei ist, dass alle wichtigen Elemente des Prozesses in einem System integriert und so Verbindungen zwischen den einzelnen Prozessartefakten hergestellt werden können. Der Vortrag zeigt wie ein kompletter Entwicklungsprozess mit VSTS abgebildet werden kann. Als Beispiel wurde hierzu bewusst ein agiler Prozess gewählt der vor allem auch für kleinere Entwicklungsteams geeignet ist. Dabei werden die wesentlichen Funktionselemente von Visual Studio Team System und Team Foundation vorgestellt und deren Nutzung im Prozess gezeigt. | | Reporting mit dem TFS | Der Team Foundation Server bietet umfangreiche Projekt-Kennzahlen. Neben Prozess- und Qualitätskennzahlen sowie verschiendenen Planungskenngrößen können auch weitere Daten wie z.B. zum Build-Prozess oder aus der Quellcode-Verwaltung ausgewertet werden. Hierbei stehen mit den SQL Server Reporting Services und Excel zwei leistungsfähige Tool zur Verfügung, diese Daten zu visualisieren. Der Vortrag zeigt anhand verschiedenen Beispielen auf, wie individuelle Auswertungen erstellt werden können und welche Möglichkeiten sich damit eröffnen. |
James Manning beschreibt auf seinem Blog, wie man andere Tools für den Content diff / merge einbinden kann. Das ganze funktioniert auch in Abhängigkeit zur File-Extension, so dass man z.B. für Word-Dokumente einen Vergleich von Versionen direkt mit der TFS Quellcode-Verwaltung bewerkstelligen kann. Ich habe das mal für Word-Dokumente getestet: 1.) Diff Doc runterladen und installieren 2.) Einstellungen im VS unter Tools / Options / Source Control / Visual Studio Team Foundation Server und dann auf Configure User Tools klicken. 3.) Für die Endung .docx das Diff Doc konfigurieren 4.) Aus der Source Control einen Compare für ein Word-File aufrufen 5.) Geniesen Weitere Infos hier: James Manning's blog : diff/merge configuration in Team Foundation - common Command and Argument values
Standardmäßig stellt Visual Studio die Prozessor-.Architektur für Anwendungen auf "Any CPU". Vor allem mit Bibliotheken gibt es damit allerdings öfters Probleme auf x64 Systemen, wenn die Bibliotheken unter 64Bit Betriebssystemen nicht sauber laufen. Eine Möglichkeit ist, die Anwendung explizit für x86 zu kompilieren, dann wird diese auch auf x64 Systemen im 32Bit Modus ausgeführt (siehe auch den Blogeintrag zur TFS-API unter x64).  Allerdings muss man hier mit ClickOnce ein wenig vorsichtig sein. Wenn man eine Anwendung zunächst mit "Any CPU" über ClickOnce verteilt hat und anschließend auf x86 umstellt, dann meldet ClickOnce „The deployment identity does not match the subscription” bzw. „Die Bereitstellungsidentität stimmt nicht mit dem Abonnement überein.“ Verschiedene Einträge im Internet verweisen zunächst darauf, dass das Zertifikat das Problem sein könnte. Da wir in der Zwischenzeit bei uns eine Domänen-Umstellung hatte, war diese Erklärung zunächst auch sehr plausibel. Dann stellte sich allerdings heraus, dass dieses Problem durch die Prozessor-Architektur verursacht wird. ClickOnce verwendet diese wohl als sog. "subscription identity" und behauptet einfach, dass es sich dabei um eine andere Anwendung handelt. Um das Problem zu umgehen sollte man also bereits beim ersten Demployment sehr gut überlegen, ob man die Anwendung nicht unter dem x86-Modus kompiliert.
Am morgigen Dienstag findet um 18:00 das nächste Treffen der .net Developer-Group Ulm statt. Thema ist dann die Windows Presentation Foundation. Als Sprecher konnten wir Gerhard Jaros von der EPS Software GmbH gwinnen, der uns fundierte Einblicke in diese immer noch recht neue Technologie geben wird. Der Abstract zum Vortrag lautet: Windows Presentation Foundation ... nach 20 Jahren hat Microsoft uns Entwicklern nun eine neue Alternative gegeben, mit Hilfe derer wir flexible User Interfaces erstellen können. Wir sind plötzlich nicht mehr gezwungen, einen Standard zu verwenden, der sich im Laufe der Zeit entwickelt hat. Buttons können bunt sein, Masken rund, transparent und farbenfroh. Wie aber geht das, wozu brauchen wir es und was bringt es uns? Wir brauchen es. Dringender denn je. Wir wollen Interfaces schaffen, die keine weitere Erklärung mehr benötigen, weil der Anwender sie aufgrund des logischen Aufbaues selbst versteht. Diese Themen werden im Workshop behandelt: - Aufbau von WPF
- Einfache WPF-Codebeispiele
- Tipps & Tricks / best practices
- Wann soll man WPF verwenden und wann nicht?
Noch dazu hat man bei dieser Gelegenheit auch Silverlight entwickelt, und so kann man erstmals mit ein und derselben Sprache sowohl für Windows-Applikation als auch für Web- Anwendungen Frontends erstellen. Es wird also in diesem Zusammenhang auch auf Silverlight verwiesen. Weitere Informationen unter www.dotnet-ulm.de
Über die API mit der man selber Anwendungen für den Team Foundation Server schreiben kann, habe ich ja schon mehrfach berichtet. Nun soll das SDK verbessert werden, was offen gestanden, auch mal Zeit wird. Brian Harry hat ein erstes Sample bereits vorab veröffentlicht, das zeigt, wie man mit der API auf die Version Control zugreift. bharry's WebLog : Working on TFS SDK improvements
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
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.
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. Nachtrag: Einen Punkt muss ich zu dem oben geschriebenen noch klarstellen. Das Problem für UI-Tests mit dieser Methode ist, dass die Web-Controls keine AutomationID veröffentlichen. Somit gibt es keine Möglichkeit diese entsprechend aus dem Automatisierungscode anzusprechen. Die Runtime-ID ist in diesem Fall leider nicht wirklich brauchbar. Ich hatte gehofft, dass der IE8 hier eine Verbesserung bringt, was aber leider nicht der Fall ist. Somit ist dies momentan leider nur ein schöner Ansatz, der in der Realität nicht recht funktioniert.
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.

Microsoft ist ja ein Meister darin, das Thema Lizenzierung zu einer WIssenschaft zu machen und inzwischen gibt es wohl Leute, die ihr Geld damit verdienen, Firmen durch den Lizenz-Dschungel von MS zu führen. Für alle, die Fragen bezgl. der Lizenzierung von Visual Studio Team System 2008 haben, sei dieses Dokument empfohlen. Fragen dazu aber bitte nicht an mich Download details: Visual Studio Team System Licensing
Die Videos zu den Sessions vom Launch-Event in Frankfurt im Februar sind jetzt für alle frei verfügbar. Ich hatte ja die Möglichkeit, am Ende einer Session von Christian Binder kurz vorzustellen, wie wir den TFS in unserem Entwicklungsprozess nutzen. Das Video kann man hier abrufen. Mein Einsatz beginnt dann ab der Minute 54. Mein Video, das ich in dem Vortrag nutze, kann hier heruntergeladen werden. War echt ne coole Sache vor mehr als 500 Leuten zu reden. Visual Studio 2008 Team System 2008 - {Überblick}
Welche Funktion finde ich in welcher Edition von Visual Studio? Wie unterscheiden sich VS Standard und VS Professional? Wann brauche ich eine Team Edition? Fragen wie diese beantwortet die Visual Studio Product Comparison. Visual Studio 2008 Product Comparison
Beim Checkin in den TFS können beim Checkin Workitems verknüpft werden. Hier können standardäßig zwei verschiedene Chck-In Actions ausgewählt werden. Associate verknüpft den Checkin nur mit dem Workitem währen Resolve das Workitem auf geschlossen setzt. Vor allem wenn man Workuiems mit größerem Umfang plant, kann es vorkommen, dass man als Default-Einstellung Associate haben möchte statt Resolve. Leider funktioniert das nicht so. Einen Workaround stellt Martin Woodward vor. Mit seiner Methode wird Resolved einfach aus den Check-In Actions entfernt und damit Associate automatisch als Default-Wert verwendet. Der Nachteil bei dieser Lösung: Man muss die Workitems außerhalb des Checkin-Prozesses auf Resolved setzen. Das ist nicht besonders schön, aber momentan leider die einzige Möglichkeit das Standard-Verhalten zu ändern. Martin Woodward: TFS Top Tip #3: Removing the Resolve Check-In Action from a Work Item
Oft hat man einen bestimmten Ordner, auf den man of zugreifen muss. Hier ist mir nun ein Feature von Vista aufgefallen (gab es wohl auch schon in früheren Windows-Versionen, aber da habe ich das gar nicht bemerkt). Man kann Toolbars einrichten und diese einfach oben, rechts oder links am Desktop andocken. Mit der AutoHide-Funktion benötigen die Toolbars auch keinen unnötigen Platz. Ein nettes Feature, das ich bei meinen Vorträgen gut gebrauchen kann. Das Video zeigt, wie's gemacht wird.
Auch wenn das unter dem Gesichtspunkt Traceability äußerst problematisch ist, gibt es im TFS 2008 die Möglichkeit Workitems zu löschen - ein Feature das oftmals gefordert wurde. Dazu benötigt man die TFS Powertools. Danach kann man mit folgendem Befehl ein Workitem löschen: tfpt destroywi /server:sartfsx01 /workitemID:8719
Ich war in den letzten Tagen auf der TeamConf 2008 in München. Es war sehr schön zu sehen, dass Team System inzwischen recht gut etabliert. Es gab auf dieser Konferenz eine ganze Reihe von Praxisberichten die darstellten, welche Erfahrungen Anwender bereits mit Team System gesammelt haben. Und es war sehr interessant, mit vielen Leuten aus dem ALM-Umfeld zu diskutieren. Ein persönliches Highlight war für mich, ein Treffen mit Sam Guckenheimer, Group Product Planner bei Microsoft, der sich unseren WorkitemManager angesehen hat und mit dem ich einige Ideen diskutieren konnte.
Ich habe auf der TeamConf einen Vortrag zu Programmierung mit dem TFS API am Beispiel einer hierarchsichen Workitem-Organisation gehalten.
Mit dem Team Foundation Server Power Tools March 2008 gibt es ein cooles Features, Workitem Templates. Haben Sie sich nicht schon mal geärgert, dass Sie beim Anlegen eines Bugs immer den Namen des gleichen Entwicklers eingeben müssen oder dass sie immer die aktuelle Iteration auswählen müssen? Genau hier helfen Workitem-Templates weiter. Und das geht so: Nach der Installation der Power Tools gibt es im Team Explorer eine neuen Knoten "Work Item Templates". Hier können neue Templates angelegt werden. Für jeden Workitem-Typ können beliebig viele Templates angelegt werden. Hier können nun die gewünschten Felder vorbelegt werden. Auf Basis dieses Templates kann nun ein neues Workitem erstellt werden (Rechter Mausklick auf das Template) oder auf ein bestehendes Template angewandt werden. Weitere Informationen finden sich in der oder auf dem Blog von Brian Harry
 Zusammen mit Christian Binder habe ich einen MSDN Webcast zum Thema UI-Testing mit dem UI Automation Framework erstellt. Der Webcast zeigt, wie man mit dem UI Automation Framework Anwendungen aus einer anderen Anwendung heraus steuern kann. Diese Methode eignet sich sehr gut um z.B. Unit-Tests zu erstellen, die die Oberfläche einer Anwendung testen. Damit lassen sich Oberflächentests sehr schön automatisieren. Und das beste ist, dass UI Automation Framework ist Bestandteil des .Net Framework 3.0 und damit kostenlos. Download des Webcasts
Gerade hatte ich eine vermeintlich Fragestellung. ich wollte einfach nur wissen, wieviel Platz auf einem Laufwerk im Netzwerk noch frei ist. Das hat sich aber als problematischer herausgestellt als gedacht, da ich nur eine Freigabe auf dem Laufwerk hatte. Das ist wohl gar nicht so einfach, damit herauszufinden, wieviel Platz auf der entsprechenden Platte noch frei ist. Erst über die gute alte Command-Shell und den dir-Befehl hat das geklappt. Damit wird der freie Plattenplatz problemlos angezeigt. Na ja, es scheint manchmal wirklich so, dass früher einiges besser war  
Möchte man aus Anwendungen wie z.B. Word auf Dokumente auf einem SharePoint Portal zugreifen. kann man dies sowohl über einen UNC-Pfad (\\ServerName\sites\SiteName) oder über eine URL (http://ServerName/sites/SiteName) zugrifen. Nöch schöner wäre allerdings, wenn man eine direkte Verknüpfung hätte, die auch im Browse-Fenster der Anwendungen genutzt werden kann. Wie man eine solche Verknüpfung einrichtet, zeige ich im folgenden Video:
Die PowerCommands for Visual Studio 2008 sind jetzt in der Version 1.1 veröffentlicht worden und bieten in dieser neuen Version einige neue Funktionen. Bei den PowertCommends for Visual Studio 2008 handelt es sich um eine kostenlose Sammlung von nützlichen Erweiterungen für die Visual Studio IDE. Einen Überblick über die Funktionen bietet dieses Dokument. Da hat es viele Sachen dabei, die sicher schon jeder beim Arbeiten mit Visual Studio 2008 vermisst hat. PowerCommands for Visual Studio 2008 - Home
Der AfterLaunch Event in Köln war eine sehr gute Veranstaltung und sehr professionell organisiert. Für die lächerliche Teilnahmegebühr von nur 8,-- € haben die Teilnehmer hochkarätige Vorträge rund um die 2008er Launch-Produkte von Microsoft erhalten. Großer Wert wurde dabei auf den Praxisbezug der Vorträge gelegt. Auch ich war dabei und hatte zwei Sessions zum Einsatz des Team Foundation Servers 2008 in der Praxis. Leider hatte ich etwas mit dem Beamer zu kämpfen, ich hoffe aber dass die Teilnehmer dennoch einige Tipps zum Einsatz des TFS mitnehmen konnte und ich den einen oder anderen animieren konnte dieses Tool nun doch einmal zu installieren und sich näher damit zu beschäftigen.

Am Donnerstag, 10.04 war ich zu Gast bei der Usergroup Braunschweig und habe dort den Vortrag zum Thema Qualitätsmanagement mit Visual Studio Team System 2008 und Team Foundation Server gehalten. Der Vortrag war für mich sehr interessant, da es eine rege Beteiligung und viele Fragen durch die Teilnehmer gab.
Vielen Dank an Lars für die Einladung.
Folien zum Vortrag
Beispielcode zum Vortrag
Wenn man aus Visual Studio einen Web-Test startet und diese Meldung bekommt, muss man die Bowser-Extensions im IE enablen.  Hierzu im IE unter Internetoptionen auf dem Reiter Advanced die Option "Enable third-party browser extensions" aktivieren. Dann kann der Web Test Recorder im IE ausgeführt werden. 
Ich halte momentan eine Vorleseung bei der Berufsakademie Heidenheim mit dem Titel "Implementierung verteilter Anwendungen auf Basis von Microsoft .NET". Im Zentrum dabei steht natürlich WCF. Hier nun die Folien und das WCF-Demo vom ersten Tag. Die Demos der beiden folgenden Termine werde ich hier auch noch veröffentlichen. Folien (Powerpoint 2007) Folien (PDF) Code
Habe gerade die neue Infragistics Netadvantage Suite 2008.1 intalliert. Bei der Installation der ASP-Komponenten muss man allerdings eine kleine Einstellung machen, sonst erhält mein einen "Fatal error". Erst wenn man in den Windows Features die IIS6 Management Compatibility aktiviert hat, klappt die Installation 
Zusammen mit meinem Kollegen Mark werde ich am 22.04.08 bei der UG München den Vortrag zum Thema Qualitätsmanagement mit VSTS nachholen. Thema des Vortrags: Dass Qualitätsmanagement heute ein fester Bestandteil eines modernen Entwicklungsprozesses sein sollte, ist inzwischen - zumindest in der Theorie – keine Frage mehr. Die Wirklichkeit ist aber leider immer noch sehr häufig eine andere. Woran liegt das? Terminstress, sich ändernde Anforderungen im Projektverlauf und in vielen Fällen ein erheblicher bürokratischer Overhead bei der Ausführung von QM vereitelt erfolgreich, die definierten Maßnahmen auch zu leben. Die Test-Tools von Visual Studio hat wohl schon fast jeder einmal gesehen, evtl. auch genutzt. Entscheidend beim Einsatz dieser Tools ist aber die Integration in den Gesamtprozess. So besteht ein erfolgreiches QM nicht nur aus Tests, sondern auch Requirementmanagement, Releasemanagement, Testability und andere Aspekte spielen hierbei eine wichtige Rolle. Die Kunst besteht darin, diese verschiedenen Aspekte über den Gesamtprozess miteinander zu verbinden. Wie dieses Ziel mit VSTS und TFS erreicht werden kann, zeigt der Vortrag. Die ideale Zielgruppe für diesen Vortrag sind: Entwickler, Qualitätsmanager, Testexperten und IT-Entscheider mit der Bereitschaft, sich auch das ein oder andere Prozessdetail live anzusehen. Weitere Details finden sich hier
Mit der Versionsverwaltung im Team Foundation Server kann man ja bekannter maßen nicht nur Code verwalten, sondern auch andere Dateien wie z.B. SQL-Skripte, Dokumentationen etc. Hierzu ist es sinnvoll, entsprechende Ordner anzulegen. Doch das will manchmal nicht recht gelingen. Will man unterhalb dem Root eines Projektes einen neuen Ordner anlegen, kann es vorkommen, dass der Button dazu disabled ist. Der Grund dafür ist einfach (wenn man's weiß). Ein Blick in den Workspace verdeutlicht das Problem. Hier sieht man, dass im Workspace ein Mapping für den Unterordner "Benutzerverwaltung" eingerichtet ist. Da die Versionsverwaltung alle Operationen, also auch das Anlegen eines neuen Ordners aber auf dem lokalen Pfad ausführen muss, tritt hier ein Problem auf. Die Anwendung weiß nicht, wo sie den Ordner lokal anlegen soll. Abhilfe schafft hier, wenn man das Mapping auf der Projkektebene einstellt, also so: Alternativ kann man natürlich auch ein separates Mapping für den Root-Ordner des Projektes einrichten. Jetzt kann der Ordner lokal einem gültigen Pfad zugeordnet werden und der Button ist auch wieder enabled.
In loser Folge schreibe ich über besonders gute oder schlechte Bücher an dieser Stelle. Nun habe ich vor Kurzem das Buch ScharePoint & Co gelesen und finde dieses Buch durchaus empfehlenswert. Gleich vorneweg, das Buch enthält keine Informationen, wie man für SharePoint Web-Parts entwickelt. Es war für mich als Entwickler aber dennoch sehr interessant, weil es sehr gut die verschiedenen Einsatzmöglichkeiten von SharePoint in Zusammenarbeit mit anderen Office-Anwendungen beschreibt. Es wird anhand verschiedener praxisorientierter Beispiele gezeigt wie man Daten in Excel- oder Access-Tabellen innerhalb von SharePoint nutzt, wie man auf der SharePoint Plattform Kommunikation effizient gestaltet, z.B. mit dem Exchange-Server oder Groove, wie man InfoPath-Formulare nutzt und wie man mit dem SQL-Server Business Intelligence realisiert. Das Buch hat mir die eine oder andere Möglichkeit aufgezeigt, die ich bisher noch nicht kannte und wo ich früher vielleicht erst mal selbst ein WebPart oder eine andere Lösung geschrieben hätte. Das Buch hat mir verdeutlicht, dass SharePoint mehr kann, als ich bisher wusste. Das gibt mir die Möglichkeit, unser Portal um Funktionen zu erweitern, die bisher wegen zu viel Aufwand einfach außen vor geblieben sind. Aus meiner Sicht ein absolut empfehlenswertes Buch, auch für Entwickler.  SharePoint & Co. - Technologien und Tools im Teamwork von MindBusiness und HanseVision erschienen bei Microsoft-Press
Über das PropertyGrid-Control habe ich ja mehrmals gebloggt (z.B. hier). Dieses Control verwendie ich recht häufig um z.B. den Inhalt eigene Konfigurations-Klassen zu editieren. Zusammen mit der XML-Serialisierung lassen sich so sehr flexible Konfigurationsmöglichkeiten schaffen. Nun hatte ich die Anforderung eine dynamische Datenstruktur an ein PropertyGrid zu binden. Da stand ich zunächst vor einem Problem. Bisher habe ich nur Objekte mit Properties unterschiedlicher Typen an das PropertyGrid gebunden. Nun habe ich eine Liste von Objekten, die die Elemente im PropertyGrid beschreiben. Wie aber diese an das PropertyGrid binden? Das schöne ist, das das PropertyGrid sich hier als sehr flexibel erweist. Man muss folgende Schritte durchführen: - Man brauch eine Klasse für ein einzelnes Property
- Dann brauchen wir eine Collection für diese Properties. Diese leiten wir von CollectionBase und ICustomTypeDescriptor ab und implementieren die Interfaces. Entscheidend ist hier die Methode GetProperties. Hier werden nun ine PropertyDescriptionCollection aus unseren Properties aufgebaut. Diese Methode ruft das PropertyGrid auf um sich dieProperties zu besorgen, die es rendern soll. Hier können wir nun also von einer belibigen Datenstruktur die benötigten
Informationen für das PropertyGrid aufbauen. - Dafür brauch wir jetzt noch einen cCustomPropertyDescriptor. Diesen leiten wir von PropertyDescriptor ab und implementieren es.
- Nun können wir unsere Properties aufbauen und an das PropertyGrid binden. Ich habe das CustomPropertyGrid als eigenes Control angelegt. Der Code ist nun sehr simpel:
1: private void Form1_Load(object sender, EventArgs e) 2: { 3: cPropertyCollection props = new cPropertyCollection(); 4: props.Add(new cPropertyItem("BoolValue", "This is a boolean value", false, true, "Properties")); 5: props.Add(new cPropertyItem("StringValue", "This is a string value", false, "Test123", "Properties")); 6: props.Add(new cPropertyItem("Folder", "Path for folder", false, "", "Path")); 7: 8: this.artisoPropertyGrid1.SelectedObject = props; 9: }
Damit erhält man folgendes Ergebnis. Man sieht die dynamisch angelegten Properties mit ihrem Name, in die Kategorien untergliedert und mit der Beschreibung. Das PropertyGrid wählt automatisch die gewohnten Controls abhängig vom Datentyp aus.
Dis ist schon ganz nett. Ich möchte aber für das Folder-Property einen entsprechenden Editor angeben können. Bei statischen Klassen vrwendet man einfach Attribute, aber bei dynamischen? Dazu wird die verfügbare Dokumentation sehr, sehr dünn. Hierzu haben wir auf der Property-Klasse eine Attribute-Arary. Diese Attribute können wir nun in der GetProperties-Klasse an den cCostomPropertyDescriptor übergeben. Der Aufbau der Properties sieht dann so aus:
1: private void Form1_Load(object sender, EventArgs e) 2: { 3: cPropertyCollection props = new cPropertyCollection(); 4: props.Add(new cPropertyItem("BoolValue", "This is a boolean value", false, true, "Properties")); 5: props.Add(new cPropertyItem("StringValue", "This is a string value", false, "Test123", "Properties")); 6: props.Add(new cPropertyItem("Folder", "Path for folder", false, "", "Path", 7: new TypeConverterAttribute(), 8: new EditorAttribute(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(System.Drawing.Design.UITypeEditor)))); 9: 10: this.artisoPropertyGrid1.SelectedObject = props; 11: }
Nun kann man im Feld für den Wert für das Property "Folder" auf einen Button klicken und erhält einen Dialog zur Auswahl eines Verzeichnisses.
Bei der Neuinstallation eines Entwicklungsrechners dauert es immer ewig, bis man sich die ganzen nützlichen Helferlein zusammengesucht hat, die man im Laufe der Zeit zu schätzen gelernt hat. Deshalb habe ich mir gedacht, ich schreibe mir mal eine Liste, die ich dann immer wieder ergänzen kann. Und vielleicht ist für den einen oder anderen da auch noch was interessantes dabei. Also so könnte ein Entwicklungsrechner aussehen: Betriebsystem / Standardanwendungen: - Windows Vista Ultimate
- Office 2007
- SQL-Server 2005 Express
- SQL-Server 2005 Management Studio
Entwicklungsumgebung: Tools Stand 13.04.2008 To be continued...
Doch einigermaßen überraschend fand ich gestern eine Mail in meinem Postfach: Sehr geehrte(r) Thomas Schissler, Herzlichen Glückwunsch! Wir freuen uns, Ihnen den Microsoft® MVP Award 2008 verleihen zu können. Mit dem MVP Award danken wir Ihnen für Ihren Einsatz für die Community, mit dem Sie Tag für Tag dazu beitragen, das Leben der Menschen zu bereichern und die Branche erfolgreicher zu machen. Wir schätzen Ihren außerordentlich bedeutenden Beitrag in den technischen Communities zum Thema Microsoft Team System im vergangenen Jahr hoch ein. Als Ausdruck unseres Dankes schickt Microsoft Ihnen bald ein MVP Award Paket zu. Damit möchten wir nochmals sagen „Danke für Ihren Einsatz“. .. Das freut mich ganz besonders. Schön dass mein Engagement hier honoriert wird. Für mich bedeutet das Ansporn und Verpflichtung, meine Community-Aktivitäten mit unvermindertem Einsatz fortzuführen.
Wer sich nicht vom Ende der Trail-Laufzeit seines TFS überraschen lassen möchte, kann ein kleines Tool verwenden. Damit kann man sich anzeigen lassen, wie lange der TFS noch laufen wird. Außerdem kann man wenn die Laufzeit nicht mehr als 10 Tage beträgt, diese auch noch einmalig um 30 Tage verlängern kann. Für eine zweiter Verlängerung braucht man eine neue Trail ID, die man bei Microsoft anfordern muss. Das Tool gibt es auch für TFS 2005 wobei ich mir kaum vorstellen kann, das heute noch jemand den TFS 2005 evaluiert. TFSVersionDetection.zip Weitere Informationen bei Brian Harry
Nachdem wir immer mehr Anfragen bezgl. unseres artsio WorkitemManager und x64 Systemen erhalten haben, haben wir hier in den letzten Tagen mal versucht, die TFS API unter Vista x64 zum Laufen zu bekommen und ich möchte das hier auch mal posten. Das Problem stellt sich in der Entwicklungsumgebung folgendermaßen dar. Direkt nach dem Start der Anwendung bekommt man folgenden Fehler: Die Assembly ist natürlich da. Die Lösung dafür ist sehr einfach. Man muss dem Projekt lediglich sagen, dass es eine x86 Anwendung ist. Dann wird es unter x64 als x86 Anwendung ausgeführt und kann damit auch die TFS API verwenden. Dazu muss man lediglich in den Eigenschaften des Projektes als Plattform explizit x86 auswählen. Nach unseren bisherigen Tests scheint damit die API auch auf x64 Systemen problemlos zu funktionieren.
Am 28.04 kommt Lars Keller, Group-Lead der .net Usergroup Braunschweig zu uns nach Ulm und wird hier einen Vortrag zu VSTO halten. Die mit Visual Studio 2008 ausgelieferte VSTO 3.0 Komponente und die frisch erschienenen VSTO Power Tools bringen zahlreiche Neuerungen für die Office Entwicklung mit sich. Ein wichtiges neues Feature in Office 2007 ist die Ribbon UI. Aber wie kann man diese anpassen? Was kann der neue Ribbon-Designer in VS 2008? Kann WPF in Office angewendet werden und wie passt LINQ dazu? Diese und weitere Fragen werden in dem Vortrag von Lars Keller behandelt. Die Theorie wird dabei durch viele kleine Live-Coding Beispiele abgerundet. Weitere Infos unter www.dotnet-ulm.de Diese Veranstaltung wird unterstützt von

Die Tatasache, dass sich Visual Studio Team System inzwischen zu einem Produkt mit einer enormen Funktionsvielfalt entwickelt hat, wird schon alleine dadurch dokumentiert, dass es vom 22.04 bis 24.04 eine Konferenz gibt, die sich nur mit diesem Produkt beschäftigt. Die Vorträge decken dabei einen großen Bereich von Projektmanagement über Qualitätsmanagement bis hin zu Best Practices und Erfahrungsberichte ab. Ich selbst werde auch mit einem Vortrag zum Thema hierarchische Workitems vertreten sein. Wer schon mal einen Blick in die Zukunft werfen möchte, dem sei der Vortrag von Christian Binder zum Thema Rosario ans Herz gelegt. Würde mich freuen, den einen oder anderen Leser meines Blogs auf der TeamConf persönlich kennen zu lernen. Wer auch dort ist, kann mir einfach einen Kommentar hinterlassen. 
Bin gerade auf das Jing-Projekt gestoßen. Damit lassen sich ganz einfach Screenshoots und Screencasts erstellen. Auf Wunsch kann man die Ergebnisse bei Screencast.com hochladen (ein kostenloser Account wird bei der Installation mit eingerichtet) oder in Flickr bzw. auf einem eigenen FTP-Server oder einem Fileshre ablegen. Werde das mal testen, ob sich damit meine Blog-Beiträge etwas aufwerten lassen.  Download Jing-Projet
Weitgehend unbemerkt von der breiten Masse der Entwickler bringt das .net Framework 3.0 auch eine Bibliothek zum Erstellen von automatisierten UI-Tests mit. Unter %PROGRAMFILES%\Reference Assemblies\Microsoft\Framework\v3.0 finden sich folgen sich die benötigten DLLs. Damit kann man UI-Tests selbst programmieren und auch in Unit-Tests integrieren. Das entspricht zwar nicht der weit verbreiteten Erwartungshaltung, die eher von einer "Record & Play" Methode ausgehen, bietet aber verschiedene Vorteile in Bezug auf Wartbarkeit und Stabilität. Ich habe hier mal ein kleines Beispiel gebaut, das den Einsatz demonstriert: Ich werde in Kürze weitere Details bloggen und verschiedene Einsatzgebiete, Erweiterungen und auch Grenzen aufzeigen. Auch ein Webcast ist zu dem Thema geplant. Bis dahin erst mal ein paar weiterführende Dokumente. Leider ist da im Moment noch nicht sehr viel publiziert worden. http://msdn2.microsoft.com/en-us/magazine/cc163288.aspx http://msdn2.microsoft.com/en-us/accessibility/bb892133.aspx Das Tool ist auf jeden Fall interessant und da es kostenlos mit dem .net Framework mitkommt, sollte jeder der sich mit Software-Tests beschäftigt mal einen Blick drauf werfen.
Mit diesem DSL Tool kann man WCF-Services einfach un komfortabel mit Hilfe eines Designers im Visual Studio bauen. Echt schick! Wie der Class-Designer hat man Two-Way-Synchronisation zwischen Code und Designer. Alle wichtigen Code-Elemente können durch den Designer erstellt werden. Schade nur, daß das Tool unter VS2008 momentan noch nicht verfügbar ist.  Ein Video in dem man das Tool in Aktion sehen kann gibt es hier. Weitere Infos und Downloads gibt es hier.
Ich bin in den nächsten Wochen wieder unterwegs Wer mich mal gerne persönlich kennenlernen möchte, gerne bei einem der folgenden Termine: | 13.03.2008 | UG Karlsruhe | Vortrag zum Thema "Qualitätsmanagement mit VSTS und TFS - für Entwickler!" | | 18.03.2008 | UG München | Vortrag zum Thema "Qualitätsmanagement mit VSTS und TFS - für Entwickler!" | | | | Dieser Vortrag ist auf einen späteren Termin verschoben. Neuer Termin wird noch bekanntgegeben | | 10.04.2008 | UG Braunschweig | Vortrag zum Thema "Qualitätsmanagement mit VSTS und TFS - für Entwickler!" | | 11.04.2008 | AfterLaunch Köln | Doppelsession zum Thema "Team Foundation Server in der Praxis" | | 24.04.2008 | TeamConf München | Vortrag zum Thema "Programmierung mit dem TFS SDK - Hierarchische Workitems im TFS 2008" | | 29.04.2008 | artiso Innovationsdialog | Innovationsdialog zum Thema "SOA in der Praxis" | | 30.04.2008 | UG Stuttgart | Vortrag zum Thema "Qualitätsmanagement mit VSTS und TFS - für Entwickler!" | | 27.05.2008 | artiso Innovationsdialog | Innovationsdialog zum Thema "Windows, Web, WCF - Oberflächentechnologien heute und in Zukunft" | | 26.06.2008 | artiso Innovationsdialog | Innovationsdialog zum Thema "Software-Architektur - das Fundament jeder Anwendung" |
Bei der Neuinstallation eines Entwicklungsrechners dauert es immer ewig, bis man sich die ganzen nützlichen Helferlein zusammengesucht hat, die man im Laufe der Zeit zu schätzen gelernt hat. Deshalb habe ich mir gedacht, ich schreibe mir mal eine Liste, die ich dann immer wieder ergänzen kann. Und vielleicht ist für den einen oder anderen da auch noch was interessantes dabei. Also so könnte ein Entwicklungsrechner aussehen: Betriebsystem / Standardanwendungen: - Windows Vista Ultimate
- Office 2007
- SQL-Server 2005 Express
- SQL-Server 2005 Management Studio
Entwicklungsumgebung: Tools Stand 12.03.2008 To be continued...
Die Frage "Wie lösche ich ein Team Projekt von meinem Team Foundation Server?" taucht immer wieder auf. Deshalb hier ein paar Infos dazu: 1.) Im Sourcecontrolexplorer kann man nur Dateien aus der Quellcodeverwaltung löschen 2.) Auch mit dem Commandozeilentool tf delete werden nur Quellcode-Dateien gelöscht. 3.) Zum Löschen eines kompletten Team-Projekts verwendet man das Commandozeilentool TfsDeleteProject /server:myteamserver “My Project“
Beim Betrieb des TFS gibt es hin und wieder Probleme mit dem lokalen Cahce. Vor allem wenn man mit mehreren Servern arbeitet, kommt es da immer wieder mal zu Problemen. Diese lassen sich durch Löschen des Caches lösen.Für mich selbst zur Erinnerung hier nochmals die Pfade: Unter XP: C:\Dokumente und Einstellungen\<User>\Lokale Einstellungen\Anwendungsdaten\Microsoft\Team Foundation\2.0\Cache Unter Vista: C:\Users\<User>\AppData\Local\Microsoft\Team Foundation\2.0\Cache
Um SQL-Projekte aus dem Management-Studio mit der Versionsverwaltung des Team Foundation Server zu verwalten gibt es einen recht einfachen Weg. Zunächst muss der MSSCCI-Provider installiert werden. Dann geht man im Management-Studio unter Tools / Options auf Source_Control und prüft, ob der richtige Provider eingestellt ist. Dann kann man seine Management-Studio Projekte einfach in die Quellcode-Verwaltung einfügen, wie man das aus Visual Studio gewohnt ist. Also einfach rechte Maustaste auf die Solution und Add Solution to Source Control. Nach der Auswahl des Servers und erfolgter Anmeldung wählt man den Ordner in der Versionsverwaltung aus. Und schon kann man seine SQL-Scripts in der Versionsverwaltung auschecken, einchecken etc. 
Ich bin gerade von der BASTA! Spring zurückgekehrt. Ich hatte dort 2 Vorträge.
Der absolute Oberknüller war mein erster Vortrag:
Beginn: 17:30 Uhr Thema: Qualitätsmanagement mit VSTS
ich hatte mich eigentlich schon darauf eingestellt, in einer kleinen überschaubaren Runde das Thema mit zwei Leuten zu diskutieren, die sich eigentlich nur verlaufen haben oder in den anderen Sessions keinen Platz mehr bekommen haben. Aber was soll ich sagen. Die Bude war voll! Den Vortrag haben sich ca. 50 Leute angehört und keiner ist vorzeitig gegangen oder eingeschlafen (glaube ich mal). Ich habe dann in dem Vortrag versucht, das Tooling aus dem VSTS, das bereits einige Speaker vor mir vorgestellt haben, in einen Prozess einzubinden, damit am Ende möglichst viel Qualität rauskommen. Danke für das große Interesse.
Hier noch meine Folien zu dem Vortrag:
Die zweite Session war zum Thema Programmierung mit dem TFS SDK.
Zu diesem Vortrag gibt es die
Folien, das
Demo  und auch noch das Video, das ich ganz am Anfang gezeigt habe.
Das TFS DataWarehouse wird standardmäßig jede Stunde aktualisiert. Das kann oft zu lange sein, gerade wenn man Reports neu anlegt. Will man nicht bis zur nächsten automatischen Aktualisierung warten, kann man das auch manuell anstarten. Hierzu ruft man die folgende URL auf dem TFS Application Tier auf: http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=Run Dann einfach auf Invoke klicken uns schon startet der Aktualisierungs-Prozess
Das Veröffentlichen von Test Results auf dem TFS-Server ist eine schöne Sache, die vor allem die Kommunikation zwischen Tester und Entwickler erleichtert Aber damit gibt es immer wieder Probleme. Ich hatte gerade so einen Fall und möchte den hier kurz beschreiben, vielleicht kann jemand anderer sich damit Zeit sparen. Nach dem Publish erhielt ich immer die Meldung "The test result share \\notebook_thomas\builds\WVBuild_20080226.3\TestResults\41577b87-2935-473c-bf03-423c777cd030 is not accessible. You might not have permission to use this network resource. Contact the administrator of this server to find out if you have access permissions. Failed to upload test run results to the drop location '\\notebook_thomas\builds'. Ask your server administrator to make the drop location available." Das Problem liegt, wie sich aus der Fehlermeldung vermuten lässt, in den Berechtigungen. Ich hatte als Szenario den Build-Agent auf dem selben Rechner eingerichtet, auf dem ich auch entwickle. Wichtig sind hier zwei Dinge: - Es müssen die Berechtigungen auf dem Verzeichnis und auf dem Build Share eingerichtet sein.
- Es müssen Berechtigungen für den lokalen User eingerichtet sein.
Bei mir war Punkt 2 das Problem. Ich hatte für den lokalen Benutzer, mit dem ich im Visual Studio arbeite, keine Berechtigungen auf dem Share, deshalb diese Meldung. Nachdem ich diese Berechtigung eingetragen habe, funktionierte es ohne Probleme.
In den letzten Tagen wurde ich häufiger gefragt, welche Edition von Visual Studio man benötigt, um mit dem Team Foundation Server zu arbeiten. Viele sind irrtümlicherweise der Meinung, dass der TFS nur mit dem VSTS zusammenarbeitet, aber das stimmt glücklicherweise nicht. Bereits ab der Standard-Edition wird der Team-Explorer in Visual Studio integriert und man hat Zugriff auf die Quellcode-Verwaltung und Workitems, wie man das auch aus dem VSTS zusammen mit dem TFS gewohnt ist. Da der Team-Explorer sich ja auch als Standalone installieren lässt, wäre theoretisch auch ein Arbeiten mit der Express-Edition möglich, aber das ist natürlich nicht mehr sehr komfortabel. Ich würde aber auf jeden Fall dei Professional-Edition von Visual Studio 2008 empfehlen, da diese nun auch Unit-Tests unterstützt und für einen normalen Entwickler damit eigentlich ausreichend sein sollte.
Brian Harry beschreibt in diesem Beitrag verschiedene Upgrade-Szenarien, so z.B. auch wie eine Workgroup-Edition auf eine Full Version upgegraded (furchtbar diese Entwickler, können einfach kein Deutsch, hat jemand dafür eine Übersetzung?) werden kann. Danke an Lars für den Link bharry's WebLog : How do I upgrade to TFS 2008?
In Köln wird von den regionalen Communities ein Event organisiert. Für alle, die den Launch-Event von Microsoft in Frankfurt verpasst haben oder denen dabei die Praxis etwas zu kurz kam, sollten sich diesen Event vormerken. Ich selbst werde dort in 2 Tracks einen Überblick über den Team Foundation Server geben. Hier noch ein paar Infos zum Event: Es braut sich etwas zusammen in Nordrhein-Westfalen! Anlässlich der Vorstellung von Windows Server 2008, SQL Server 2008 und Visual Studio 2008 haben sich die User Groups aus Bonn (Bonn-to-Code.Net), Köln (.net User Group Köln) und vom Niederrhein (VfL Niederrhein) zusammengetan, um unter der Schirmherrschaft des JustCommunity e.V. ergänzend zum offiziellen Launch ein Community-Event der besonderen Art auf die Beine zu stellen: - Ein ganzer Tag voller Vorträge, verteilt auf drei parallele Tracks
- Sprecher, die als Entwickler und IT-Professionals aus ihrer täglichen Arbeit heraus Praxiswissen vermitteln
- Große Verlosung u.a. von Windows Server 2008, SQL Server 2008 und Visual Studio 2008 (not-for-resale-Versionen)
- Vielfältige Möglichkeiten zum Networking mit anderen Teilnehmern und Firmen aus der Region
Und das zu einem Preis von 8,- Euro, in dem auch noch Verpflegung und Parkausweis enthalten sind.
AFTERLAUNCH Launch war gestern - heute ist Praxis Freitag 11. April 2008, KonferenzZentrum im Technologiepark Köln
Anmeldung und weitere Infos auf www.afterlaunch.de
Ich war die vergangenen 3 Tage auf dem Launch-Event von Microsoft in Frankfurt als ATE. Das war wirklich mal eine Konferenz wie ich Sie bisher im .Net Umfeld noch nicht kannte. 7.500 Teilnehmer! Als Veranstaltungort hatte Microsoft die Messe Frankfurt ausgewählt und durch die langläufigen Gebäude waren leider die Wege recht weit.  | Das war nur die AUssteller-Halle. Hier bekommt man eine Ahnung wie groß die Veranstaltung war. | Ich war als ATE (Ask the Expert) mit dem Schwerpunkt Team Foundation Server aktiv und habe in den 3 Tagen viele Fragen zu dem Thema beantworten können und auch viele interessante Diskussionen geführt. Schön für mich war, dass man merkte, dass der Team Foundation Server nun langsam an Fahrt aufnimmt und immer mehr Verbreitung findet. Das konnte man sicher an der Zahl der Fragen zu dem Thema ablesen und sicher hat auch die Tatsache, dass sich eine Vollversion im Give-Away-Paket der Teilnehmer befand, dazu beigetragen, das der eine oder andere sich mit dem Thema nun doch auseinandersetzt.  | Der ATE-STand | Christian Binder hatte eine ganze Reihe von Vorträgen zum Thema VSTS und hatte mich im Vorfeld gebeten, einen kleinen Praxisbericht einzubauen. Ich konnte dann in einer seiner Sessions vor rund 600 Zuschauern in 10 Min. demonstrieren, wie wir den TFS im Rahmen unseres Entwicklungsprozesses nutzen. Da eine Live-Demo in dieser Zeit unmöglich ist, habe ich eine für mich neue Präsentationsform gewählt. Ich habe die Aktionen in einem Video aufgezeichnet und das Video dann live kommentiert. Damit konnte ich dann Sequenzen in denen beispielsweise Daten erfasst werden beschleunigt ablaufen lassen und so viel Zeit sparen. Ich schätze mal Live hätte das Ganze sicher 45 Minuten gedauert. In 10 Min. einen Entwicklungsprozess vom Kundengespräch bis zur Implementierung zu zeigen, man kann sich das Tempo des Vortrags vorstellen. Für alle, denen das zu schnell ging oder wer nicht dabei war, hier ist das Video nochmal zum Download. Danke an Chris. War echt eine geile Show. Das Feedback danach auf dem ATE-Stand war einfach überwältigend. Für mich war es eine echt coole Veranstaltung und ich habe viele neue Eindrücke und Kontakte mit nach Hause genommen. Bleibt nur zu hoffen, dass das Thema TFS nun endlich die breite Masse der Entwickler erreicht - ein echt cooles Tool, das sich jeder mal anschauen sollte.
Ich war am 13.02 und 14.02 auf der VSOne und habe dort insgesamt 4 Sessions gehalten. Für mich war es eine tolle Veranstaltung, die Resonanz auf meine Vorträge war sehr positiv und ich konnte viele interessante Diskussionen mit Teilnehmern und Sprecherkollegen führen. Hier nun meine Slides und den Code zum Download: Session Requirement Management mit Team Foundation Server Bei dieser Session habe ich vorgestellt, wie wir bei uns im Hause mit Hilfe des Team Foundation Servers Requirements verwalten. Hierbei kommt auch der artiso Workitem-Manager zum Einsatz um Workitems hierarchisch zu strukturieren. Spezifikationsdokumente Verwalten Spezifikationsdokumente werden oft als monolithische Worddokumente verwaltet Daraus ergeben sich eine Reihe von Problemen, die wir mit unserem Ansatz lösen, die Spezifikation in kleine Dokumente aufzuteilen und so jede einzelne Funktion zu Spezifizieren. Hierzu nutzen wir ein Word-AddIn das Bestandteil des artiso Workitem-Managers ist. Mit 3 Schichten zum Erfolg Das war der Titel meiner Architektur-Session. Hier habe ich zunächst den Aufbau und die Vorteile einer 3-Schicht-Architektur beschrieben. Anschließend erläuterte ich Komponentenorientierung. An einem kleinen Demo-Projekt zeigte ich die Planung und den Aufbau eines Projektes vom Architekturdesign bis zur Implementierung und demonstrierte dabei einige Best Practices aus unseren Projekten. Am Ende beschrieb ich noch die Auswirkungen für verteilte Systeme. Interessant für mich war, dass der Meister der Komponentenorientierung Ralf Westphal der Session beiwohnte uund den Vortrag mit interessanten Fragen bereicherte. XML-Serialisierung zur Persistierung von Objekten XML-Serialisierung ist eine Technologie, mit der Objekte schnell und einfach in ein XML-Format überführt und auch wieder zurück konvertiert werden kann. Dies Technik ist nicht neu und viele Entwickler kennen und nutzen sie. Ich habe in der Session verschiedene Möglichkeiten aufgezeigt, wie sich XML-Serialisierung nutzen lässt, von der Persistierung von kompletten Datenobjekten über Konfigurationsdateien bis hin zur Optimierung der Speicherung von Listenobjekten in der Datenbank. Nächste Woche bin ich dann auf dem Launch Event als ATE. Das wird sicher interessant bei diesem Mega-Event (6.500 Teilnehmer!).
Wir nutzen in unserem Entwicklungsprozess seit einiger Zeit den Team Foundation Server. Für das Requirement Management setzen wir Workitems ein. In der aktuellen Version des Team Foundation Servers fehlte uns dabei bisher allerdings die Möglichkeit, Workitems hierarchisch zu organisieren. Glücklicherweise verfügt der Team Foundation Server über ein leistungsfähiges API (siehe auch meinen MSDN-Webcast zu diesem Thema). Auf Basis dieser API haben wir ein Tool, den artiso Workitem Manager, entwickelt, mit dem wir nun Workitems so strukturieren können, wie wir das in unseren Projekten brauchen. Neben der hierarchischen Struktur können auch Iterationen in Baumstrukturen abgebildet werden.  Ebenfalls Bestandteil des artiso Workitem Manger ist ein Word-AddIn mit der Spezifikationsdokumente auf Funktionsebene verwaltet werden können. Damit lassen sich verschiedene Probleme mit Spezifikationsdokumente als monolithische Worddokumente lösen.  Den artiso Workitem Manager kann als Beta-Version kostenlos heruntergeladen werden. Die frei verfügbare Version ist auf 50 Workitems begrenzt. Weitere Informationen finden sich hier.
...sollte man sich mal die AsyncPostbackTriggers anschaen, evtl. liegt das Proble dort begraben. Aber erst mal der Reihe nach. Ich hatte eine Web-Seite, die sich plötzlich nicht mehr aufrufen lies. Ich habe unterschiedliche Fehler erhalten. Mit dem IIS wurde einfach angezeigt, dass die Seite nicht verfügbar ist, im Debug meldete Visual Studio eine OutOfMemoryException und der Developer Web Server ist gleich mal abgeschmiert. Nach einigem Suchen haben wir dann das Problem entdeckt. Auf der Seite war ein AsyncPostbackTrigger auf eine Textbox eingetragen. Diese Textbox wurde aber irgendwann entfernt. Dies scheint das oben beschriebene Problem ausgelöst zu haben. Vielleicht hat ja mal jemend einen ähnlichen Fehler und kann ihn mit dieser Info schnell beheben.
Mit Hilfe der neuen Extension Methods in C# 3.0 können einfache Matrizenoperationen ganz einfach als Methoden auf bestehende Objekttypen eingefügt werden. Ich habe hier mal ein Beispiel mit SortedDictionaries. Diese Extension Method erlaubt das addieren zweier Matrizen. public static void AddDictionary(this SortedDictionary<int, decimal> resultDictionary, SortedDictionary<int, decimal> insertDictionary)
{
foreach (int key in insertDictionary.Keys)
{
if (!resultDictionary.ContainsKey(key))
resultDictionary.Add(key, insertDictionary[key]);
else
resultDictionary[key] += insertDictionary[key];
}
}
Der Aufruf gestaltet sich dann sehr einfach:
SortedDictionary<int, decimal> a = new SortedDictionary();
SortedDictionary<int, decimal> b = new SortedDictionary();
//Werte in Dictionaries einfügen
a.AddDictionary(b);
Ich finde die Extension Methods ne feine Sache. Natürlich sind auch beliebige andere Operationen möglich.
Des TFS SDK enthält ein Control um Workitems in Winforms zu bearbeiten. Dieses Control löst damit das Problem, wie die hochflexible Struktur von Workitems in einer eigenen Anwendung dargestellt und bearbeitet werden kann. Mit dem neuen TFS SDK 2008 gibt es allerdings ein kleines Problem beim Einsatz des Controls. Wird das Control in eine Winform eingebaut, kommt es zu einer NullReferenceException. Object reference not set to an instance of an object. Dieses Problem konnte ich bei mir umgehen, indem ich nicht die DLL aus dem SDK sondern aus dem TeamExplorer. Ich habe die beiden DLLS, die ich hier ausgetauscht habe hier zum Download bereitgestellt.
Über die TFS-API kann der Namen eines TFS-Servers einfach abgefragt werden. Dazu kann folgender Code verwendet werden: private TeamFoundationServer tfs; NetworkCredential account = new NetworkCredential(user, password); tfs = new TeamFoundationServer(server, account); string ServerName = tfs.Name; Dabei habe ich allerdings folgendes Problem festgestellt: Der Servername ist nicht konsistent. Ist der Server im Team-Explorer noch nicht geristriert, enthält der Servername auch den Port. Nachdem der Server im Team-Explorer dann registriert wurde, wird nur noch der Server-Name zurückgegeben. Das sollte man auf jeden Fall berücksichtigen, wenn man mit dem Name-Property vom tfs arbeitet.
Unter Access 2003 gabe es Access-Datenbankprojekte (*.adp) mit denen man wunderbar auf bestehende SQL-Datenbanken zugreifen konnten. Sind diese mit Access 2007 verloren gegangen? Das nicht, aber sie sind jetzt gut versteckt. Um ein Datenbankprojekt mit Access 2007 anzulegen geht man wie folgt vor: - Access ganz normal starten
- Access fragt nun nach einer Vorlage für eine neue Datei. Hier das Icon "Blank Database" auswählen.
- Im rechten Bereich kann man nun den Dateiname angeben. Hier den File-Dialog öffnen.
- In diesem Dialog kann man nun als Dateityp "Microsoft Office Access Projects" auswählen.
- Wenn mann dann auf den "Create"-Button klickt kann man noch auswählen, ob man sich zu einer bestehenden Datenbank verbinden möchte oder eine neue anlegen will. Der Rest dürfte dann wieder vertraut erscheinen.
Aus dem Fenster mit Fehlermeldungen und Wahrnungen im Visual Studio heraus kann man direkt Workitems auf dem Team Foundation Server anlegen. Dazu einfach die entsprechende Zeile mit der rechten Maustaste anklicken und im Kontextmenü "Create Work Item" wählen. Es werden automatisch Informationen in den Titel und den Verlauf übernommen, wobei meiner Meinung nach die Details eher in das Beschreibungs-Feld gehören als in den Verlauf. 
Schick ist es, wenn man in der Anwendung demBenutzer die verfügbaren SQL-Server als Auswahl anzeigt. Die kann man mit folgendem Code bewerkstelligen: using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace SQLInstances
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
DataTable dataTable = System.Data.Sql.SqlDataSourceEnumerator.Instance.GetDataSources();
foreach (DataRow datarow in dataTable.Rows)
{
string datasource = datarow["ServerName"].ToString();
if (datarow["InstanceName"] != DBNull.Value)
{
datasource += String.Format("\\{0}", datarow["InstanceName"]);
ComboBox1.Items.Add(datasource);
}
DataGridView1.DataSource = dataTable;
}
}
}
}
Das Beispiel gibt die verfügbaren SQL-Server in einem GridVie aus.
Um auch Zuisatzinformationen wie Version etc. zu erhalten, muss auf dem SQL-Server der SQL-Browser laufen:

Unter http://entwickler-press.de/ kann man einen Adventskalender öffnen. Hinter jedem Türchen steht ein e-Book zum kostenlosen Download. Aber Achtung das Türchen geht immer nur an dem jeweiligen Tag auf.
Durch Zufall habe ich gerade herausgefunden, dass man im IE auch mehrere Startseiten eintragen kann. Einfach in der Liste mehrere zeilen mit den verschiedenen URLs eingeben. Die werden dann beim Start alle geöffnet. 
Folgende Anforderung: Ich möchte in einer Tabelle, die über die gesamte Bildschirmbreite geht, den Inhalt einer Zelle scrollbar haben. Mein Ansatz: Ich mache in die Tabellenzelle ein DIV mit Overflow:auto Problem: Das funktioniert zwar im FireFox, aber nicht im IE. Der IE geht wohl her und schaut sich den Inhalt des DIVs an und macht die Tabelle dann so breit, dass der gesamte Inhalt reinpasst und berücksichtigt dabei nicht, dass das DIV ja auch scrollen könnte. Dieser Effekt tritt auf, wenn das DIV eine prozentuale Breite hat. Folgender Code verdeutlichd das Problem. Das obere DIV verhällt sich korrekt, da es nicht in eine Tabelle eingebettet ist. Bei den unteren beiden tritt aber das beschriebene Problem auf. <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="ValuePlanner_2008.Web.ProductArea.WebForm1" %>
<html>
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div style="width: 100%; overflow: auto">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<br />
<br />
</div>
<script language="javascript" type="text/javascript"> 1: 2: function fnRefreshScrollPosition(source) 3: { 4: document.getElementById("staticUnits").scrollLeft = source; 5: } 6: </script>
<div style="width: 100%">
<table style="width: 100%">
<tr>
<td style="width: 100%; height: 50px;">
<div id="staticUnits" style="width: 100%; overflow: auto;">
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb<br />
<br />
</div>
</td>
</tr>
</table>
<table style="width: 100%">
<tr>
<td style="width: 100%; height: 50px;">
<div id="units" style="width: 100%; overflow: auto;" onscroll="fnRefreshScrollPosition(this.scrollLeft);">
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc<br />
<br />
</div>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
Lösung 1: Ich kann den DIVs eine feste Breite geben. Aber eigentlich will ich ja, dass der gesamte zur Verfügung stehende Platz genutzt wird und wenn dieser nicht ausreicht gescrollt wird. Um das zu erreichen müsste ich über ein Resitze-Event die Breite der Tabellenzeile ermitteln und diese dann jedesmal auf die DIVs anwenden. Das wird aber schnell sehr hässlich wenn Margins etc. mit berücksichtigt werden müssen.
Lösung 2: Ich positioniere die DIVs einfach absolut. Dann werden Sie nicht mehr als Inhalt der Tabelle berücksichtigt und die Tabelle erstreckt sich über genau 100% der Breite. Gut nutzen kann man hier den Effekt, dass die Positionsangaben bei absoluter Poistionierung sich immer auf den Container, also in unserem Fall auf die Tabellenzelle beziehen. Ein Stolperstein dabei ist, dass das DIV natürlich auch keinen Einfluss mehr auf die Höhe der Tabellenzelle hat. Diese muss man nun explizit angeben, ich habe da einfach mal 50px vorgegeben. Der Code sieht dann so aus. Hier scrollen nun alle 3 DIVs wie gewünscht.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="ValuePlanner_2008.Web.ProductArea.WebForm1" %>
<html>
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div style="width: 100%; overflow: auto">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<br />
<br />
</div>
<script language="javascript" type="text/javascript"> 1: 2: function fnRefreshScrollPosition(source) 3: { 4: document.getElementById("staticUnits").scrollLeft = source; 5: } 6: </script>
<div style="width: 100%">
<table style="width: 100%">
<tr>
<td style="width: 100%; height: 50px;">
<div id="staticUnits" style="width: 100%; overflow: auto; position: absolute">
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb<br />
<br />
</div>
</td>
</tr>
</table>
<table style="width: 100%">
<tr>
<td style="width: 100%; height: 50px;">
<div id="units" style="width: 100%; overflow: auto; position: absolute;" onscroll="fnRefreshScrollPosition(this.scrollLeft);">
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc<br />
<br />
</div>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
Events in eigene WebUserControls (.ascx) einzubauen ist im Prinzip ganz einfach: 1: public event ClickEventHandler Clicked; 2: public delegate void ClickEventHandler(object sender, EventArgs e); 3: protected virtual void OnClicked(EventArgs e) 4: { 5: if (Clicked != null) 6: Clicked(this, e); 7: }
Man deviniert ein Event mit einem Eventhandler-Typ (Zeile1), definiert einen Delegaten für den Eventhandler (Zeile 2) und kann dann eine Methode definieren, die den Event auslöst. Diese Methode ruft man dann auf, wenn das Event ausgelöst werden soll.
Wenn man das UserControl in eine Seite einbaut kann man jetzt im CodeBehind ganz einfach einen Eventhandler auf den Event registrieren und fertig:
this.ucButton.Clicked += new ClickEventHandler(ucButton_Clicked);
Auch im Markup kann man den Event angeben, vorausgesetzt man hat den entsprechenden Eventhandler angelegt.
<uc3:ucButton ID="ucButton" runat="server" Text="Gross" ImageURL="~/Images/Status/GreenBox.png" OnClicked="ucButton_Clicked" /> Was bei mir aber nicht funktioniert, ist der Designtime-Support. Bei anderen Controls kann ich die Events im Property-Grid sehen und ich kann per Doppelclick auch einen Standard-Eventhandler einrichten und registrieren. Das geht bei mir nicht. Hat jemand dafür eine Lösung? Wenn ja, dann bitte her damit.
Sicher ein alter Hut, aber für mich war's gerade neu und ich finde das echt klasse. Mit CSS kann man Elemente auch mit einem Abstand zum rechten Rand positionieren. <DIV style="position:absolute; right:20px; top:350px; width:300px; height:150px;"></DIV> erzeugt ein DIV das immer exakt 20px vom Rechten Rand entfernt ist, auch nach einem Resize des Fensters. Genauc das was ich gerade brauche. Man muss dabei nur beschten, dass right offensichtlich die schwächste Einstellung ist, d.h. wenn left und width ebenfalls angegeben sind, wird right ignoriert. Wenn aber nur zwei der Werte angegeben sind, wird der dritte automatisch ermittelt, also z.B. bei left und right wird die Breite automatisch angepasst. Das selbe funktioniert natürlich auch mit top, bottom und height.
Im TFS 2008 hat Microsoft endlich die Lizenzbedingungen angepasst. Für folgende Aktionen wird nun keine CAL mehr benötigt: - Anlegen eines Workitems
- Anzeigen der Workitems, die ein Benutzer selbst angelegt hat
- Bearbeiten der Workitems außer Änderung des Status des Workitems
Damit ist es nun endlich möglich, Kunden etc. in das Projekt besser einzubinden, ohne dafür Unsummen für CALs auszugeben. adamga's WebLog : TFS for Defect Tracking! Licensing Change!!!
Bei unserem heutigen Treffen der .Net Developer-Group Ulm hatten wir einen Vortrag zum Thema SQL-Projekte. Dabei kam die Frage auf, ob man Daten einer Datenbank nicht in ein SQL-Skript exportieren kann, das dann alle Daten über Insert-Statements einfügen kann. Ich habe hierzu eine Lösung in Visual Studio 2008 gefunden und das geht so:
1.) Server Explorer öffnen und die entsprechende Verbindung rechts anklicken, dann "Publish to provider" auswählen.
2.) Dann die Datebank auswählen und darunter die Checkbox disablen (außer man will wirklich die Datenbank komplett scripten).
3.) Die nächsten Schritte sind dann soweit selbsterklären. In dieser Maske kann man dann auswählen, ob man Daten, Schema oder beides scripten möchte:
4. In dem erzeugten Script steht dan z.B. so etwas:
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'ALFKI', N'Alfreds Futterkiste', N'Maria Anders', N'Sales Representative', N'Obere Str. 57', N'Berlin', NULL, N'12209', N'Germany', N'030-0074321', N'030-0076545')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'ANATR', N'Ana Trujillo Emparedados y helados', N'Ana Trujillo', N'Owner', N'Avda. de la Constitución 2222', N'México D.F.', NULL, N'05021', N'Mexico', N'(5) 555-4729', N'(5) 555-3745')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'ANTON', N'Antonio Moreno Taquería', N'Antonio Moreno', N'Owner', N'Mataderos 2312', N'México D.F.', NULL, N'05023', N'Mexico', N'(5) 555-3932', NULL)
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'AROUT', N'Around the Horn', N'Thomas Hardy', N'Sales Representative', N'120 Hanover Sq.', N'London', NULL, N'WA1 1DP', N'UK', N'(171) 555-7788', N'(171) 555-6750')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BERGS', N'Berglunds snabbköp', N'Christina Berglund', N'Order Administrator', N'Berguvsvägen 8', N'Luleå', NULL, N'S-958 22', N'Sweden', N'0921-12 34 65', N'0921-12 34 67')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BLAUS', N'Blauer See Delikatessen', N'Hanna Moos', N'Sales Representative', N'Forsterstr. 57', N'Mannheim', NULL, N'68306', N'Germany', N'0621-08460', N'0621-08924')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BLONP', N'Blondesddsl père et fils', N'Frédérique Citeaux', N'Marketing Manager', N'24, place Kléber', N'Strasbourg', NULL, N'67000', N'France', N'88.60.15.31', N'88.60.15.32')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BOLID', N'Bólido Comidas preparadas', N'Martín Sommer', N'Owner', N'C/ Araquil, 67', N'Madrid', NULL, N'28023', N'Spain', N'(91) 555 22 82', N'(91) 555 91 99')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BONAP', N'Bon app''', N'Laurence Lebihan', N'Owner', N'12, rue des Bouchers', N'Marseille', NULL, N'13008', N'France', N'91.24.45.40', N'91.24.45.41')
Das Script lässt sich dann wunderbar in Datenbankprojekte einbauen und in der Quellcode verwqlten. Dies bietet z.B. eine gute Möglichkeit, um Testdaten für die Durchführung von Tests mit der jeweiligen Anwendungs-Version in der Quellcode-Verwaltung zu verwalten.
In Visual Studio 2005 funktioniert das leider nicht. Dort muss auf entsprechende Tools zurückgegriffen werden, z.B. den kostenlosen Oracle SQL Developer http://www.oracle.com/technology/products/database/sql_developer/index.html der übrigens auch mit SQL-Server funktioniert 
Das Problem:
Ich habe in C# ein Objekt vom Typ System.Drawing.Color. Dieses möchte ich in einen String-Konvertieren, den ich im HTML verwenden kann. Das funktioniert gut bei benannten Farben wie z.B. "red". Dort kann man Color.Name verwenden. Aber bei nicht benannten Farben liefert dies einen ARGB-Wert mit dem HTML nichts anfangen kann. Dehalb habe ich diese kleine Mthode geschrieben:
private string GetColorString(Color color)
{
if (color.ToKnownColor() != 0)
return color.Name;
else
return "#" + color.Name.Substring(2);
}
Wenn jemand eine einfachere Lösung weiss, einfach her damit!
Update:
Jürgen hat noch eine viel einfacher Lösung (siehe Kommentar) mit string htmlcolor = ColorTranslator.ToHtml(Color.Bisque) Kannte ich bisher noch nicht, aber man lernt ja nie aus!
Ein weniger bekannter Operator in C# ist der Operator ??. Damit kann ein Objekt auf null geprüft werden und wenn dies der Fall ist ein Alternativwert verwendet werden. Ein Beispiel kann das verdeutlichen: 1: object a = null; 2: object b = 5; 3: 4: object c = a ?? b;
In dem Beispiel gilt c = b. Würde in der Zeile 3 a noch entsprechend inizialisiert, dass dieses nut mehr null ist, dann würde gelten c = a.
Visual Studio 2008 liegt nun als RTM-Version zum Downloadf bereit. Wer keine MSDN-Subscription hat, kann sich hier die Trail-Versionen herunterladen. Visual Studio 2008 Trial Downloads
Ich habe bei mir eine Liste die wiederum eine Liste mit Unterobjekten enthält. Ich möchte nun daraus ein Element der Unterliste mit einer bestimmten ID selektieren. Eine klare Sache für LINQ! Als Leitfaden habe ich auf 101 LINQ Samples mir folgendes Beispiel rausgesucht: 1: public void Linq15() { 2: List customers = GetCustomerList(); 3: 4: var orders = 5: from c in customers, 6: o in c.Orders 7: where o.Total < 500.00M 8: select new {c.CustomerID, o.OrderID, o.Total}; 9: 10: ObjectDumper.Write(orders); 11: }
Das sieht ganz eifach aus, hat bei mir aber absolut nicht funktioniert. Ich konnte das schon nicht sauber eingeben, da er in Zeile 6 für c keine Intellisense-Unterstützung geboten hat. Das Ganze konnte ich dann lösen, indem ich das etwas umgestellt habe, auf das Beispiel oben übertragen sieht meine Lösung so aus:
1: public void Linq15() { 2: List customers = GetCustomerList(); 3: 4: var orders = 5: from c in customers 6: from o in c.Orders 7: where o.Total < 500.00M 8: select new {c.CustomerID, o.OrderID, o.Total}; 9: 10: ObjectDumper.Write(orders); 11: }
Ich habe einfach in Zeile 6 statt des Kommas in der vorherigen Zeile nochmals ein from eingebaut. So funktioniert es bei mir nun, wie ich mir das gewünscht habe.
Na wenigstens nimmt Visual Studio einen Absturz nicht auf die leichte Schulter sondern gibt zu, dass das eine Katastrophe ist. 
Damit Ich habe ein Web User Control bei dem ich eine TextBox als Property nach außen geben möchte, damit man die Eigenschaften der Textbox editieren kann. Das kann man durch ein paar Attribute erreichen. [Browsable(true),
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
RefreshProperties(RefreshProperties.Repaint)]
public TextBox DropDownTextbox
{
get
{
return this.TextBox1;
}
set
{
this.TextBox1 = value;
}
}
Damit werden auf dem UserControls zusätzliche Properties angelegt und zwar alle Properties einer Textbox mit dem Prefix "DropDownTexbox" also dem Namen des Properties auf dem Control.
Im Markup werden die Properties ganz normal als Attribute eingefügt. Was mich allerdings etwas gewundert hat war, dass ich im Markup über Intellisense die Textbox allerdings auch als separates Tag angeben kann und darauf meine Attribute definiere. Allerding wird das denn im Designer nicht mehr sauber gerendert.
<uc1:WebUserControl1 ID="WebUserControl11" runat="server" DropDownTextBox-BackColor="#FFCC00"> <DropDownTextbox BackColor="red"></DropDownTextbox> </uc1:WebUserControl1>
Der Team Foundation Server ist ein sehr flexibles Werkzeug. Es lässt sich an verschiedene Prozessmodelle anpassen. Die die beiden folgenden Links verweisen zu entsprechenden Kapiteln in der MSDN-Hilfe die beschreiben wie Workitem Typen und Prozessvorlagen angepasst werden können. Customizing Work Item Types Customizing Process Templates
LINQ erweitert ICollections, IEnumerable etc. mit einigen Extension Methods wie z.B. ToList() was sehr hilfreich ist. Ich hatte gerade das Problem, dass diese Extensions nicht im Intellisense angezeigt wurden. Nach einigem Suchen habe ich festgestellt, das lag daren, dass ich kein using System.Linq drin hatte, sondern nur auf System.Data.Linq und System.Data.Linq.Mapping. Nachdem ich das using ergänzt habe, funktionierte das problemlos.
Das alte Jahr ist noch nicht zu Ende undf schon verspricht das neue Jahr ereignisreich zu werden. Im Februar bin ich wieder auf Tour: 13. / 14. Feb. 2008 - VSOne in München Hier halte ich zwei Vorträge zu XML-Serialisierung und Architektur 19. / 20. Feb. 2008 - Launch Event Microsoft in Frankfurt Hier bin ich als ATE (Ask the Expert) zum Thema Visual Studio Team System 26. / 27. Feb. 2008 - BASTA! Sprint Edition in Frankfurt Auf der BASTA! werde ich zwei Vorträge zum Thema TFS halten. Weitere Details folgen noch. Ich würde mich freuen, den einen oder anderen Leser meines Blogs auf einem dieser Events persönlich kennen zu lernen.
Ich hatte gerade ein Aha-Erlebnis der etwas anderen Art. Im Infragistics-Chart gibt es eine Zoom-Funktion für die Achsen. Bei einem Composite-Chart scheint das aber nicht zu funktionieren. Ich habe folgendes im Code stehen: ChartObj.CompositeChart.ChartAreas[0].Axes[0]. Aber mein Intellisense zeigt kein passendes Property an. Im Forum steht auch die Aussage von einem Infragistics-Mitarbeiter, dass das nicht geht. Wenn ich dann "blind" das vervollständige zu ChartObj.CompositeChart.ChartAreas[0].Axes[0].ScrollScale.Visible = true;
funktioniert der Code wunderbar! Mal abgesehen davon, dass ich gar nicht wüsste, wie man Properties im Intellisense versteckt aber dennoch verfügbar macht, warum um alles in der Welt haben die Jungs dieses Property nicht öffentlich zugänglich gemacht?
Das Problem kennt vermutlich fast jeder Notebook-Besitzer der an seinem Arbeitsplatz noch einen zusätzlichen PC hat. Wenn man am Arbeitsplatz sitrzt steht das Notebook entweder nutzlos in der Ecke oder man kommt mit den Mäusen und Tastaturen immer durcheinander. Wäre es nicht schön, das Notebook am Arbeitsplatz zu integrieren. Unter XP hatte ich hier eine geniale Lösung - Maxivista. Damit konnte man sogar eine Zweischirmlösung aufbauen indem das Notebook einfach den Desktop des Arbeitsplatzrechners erweiterte. Absolut klasse, nur funktioniert der Host unter Vista nicht (zumindest nur mit den WDDM-Treibern, was für mich allerdings keine Alternative ist). Nun habe ich Synergy entdeckt. Dieses Opensource-Tool bitet die Möglichkeit, einen Rechner mit der Maus / Taststur eines zweiten Rechners fernzusteuern. Es unterschiedet sich zu Remote Desktop o. ä., indem es nicht den Bildschirm des PCs auf den Zweit-PC überträgt. Es lässt sich in meinem Szenario damit wunderbar nutzen. Ich habe auf meinem Desktop-PC Visual Studio laufen und kann dann einfach mit der Maus links zum Bildschirmrand rausfahren und schon bin ich auf meinem Notebook und kann damit mit der gleichen Tastatur / Maus z.B. Suchen im Internet, Downloads, E-Mail oder andere Funktionen aufrufen ohne dass mein Desktop-PC damit belastet wird. Das Ganze läuft auch problemlos unter Vista und ist zumindest mal ein brauchbarer Ersatz für MaxiVista.
Ich habe mir gerade ein kleines Beispiel für den Zugriff auf einen Webservice per JavaScript per AJAX zusammengebaut. Da ich hier einige Informationen aus verschiedenen Quellen zusammengetragen habe, möchte ich das Beispiel hier kurz posten, vielleicht hilft es dem einen oder anderen, einige Informationen gesammelt zu finden. Hier zunächst der Code für den Webservice: 1: namespace ValuePlanner_2008.Services 2: { 3: /// <summary> 4: /// Summary description for INNProjectExplorerWebService 5: /// </summary> 6: [WebService(Namespace = "http://tempuri.org/")] 7: [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 8: [GenerateScriptType(typeof(myData))] 9: [ToolboxItem(false)] 10: [ScriptService] 11: public class INNProjectExplorerWebService : System.Web.Services.WebService 12: { 13: [WebMethod] 14: [ScriptMethod] 15: public myData HelloWorld(int ID) 16: { 17: return new myData { ID = ID, Text = "Hello World" + ID.ToString() }; 18: } 19: } 20: 21: public class myData 22: { 23: public int ID { get; set; } 24: public string Text { get; set; } 25: } 26: }
Kurz zu erwähnen sind hier folgende Details: In Zeile 10 wird über ein entsprechndes Attribut der Webservice für die Zusammenarbeit mit AJAX konfiguriert. Das selbe gilt in Zeile 14 für die Methode, die der Webservicebereitstellt. Da die Methode einen eigenen Datentyp (myData) zurückgibt, wird in Zeile 8 dieser Typ ebenfalls für AJAX veröffentlicht. Man kan so beliebig komplexe Datenstrukturen zwichen JavaScript und dem WebService austauschen, solange diese auf Datentypen basieren, dieJavaScript auch verarbeiten kann (also z.B. keine generischen Listen etc.). Der restliche Code wird automatisch über das Webservice Template erzeugt bzw. sollte keiner weiteren Erklärung bedürfen.
In der ASPX-Seite muss ein Scriptmanager eingebaut werden und der Service darauf registriert werden. Da ich de Scriptmanager in meinem Beispiel in der Master-Page habe, verwende ich einen ScriptmanagerProxy, der es erlaubt, die Registrierungen für einzelne Seiten vorzunehmen und an den Scriptmanager in der Master-Page weiterleitet. Dies ist deshalb notwendig, da auf einer Seite nur ein einziger Scriptmanager vorkommen darf.
1: <asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server"> 2: <Services> 3: <asp:ServiceReference Path="~/Services/INNProjectExplorerWebService.asmx" /> 4: </Services> 5: </asp:ScriptManagerProxy>
Noch ein wichtiger Hinweis: Ich hatte zuerst den ToolScriptManager aus dem AJAX Component Toolkit in meiner Masterpage. Dieser scheint nicht mit dem ScriptManagerProxy zusammenzuarbeiten, jedenfalls wurde bei mir die Proxy-Klasse nicht erstellt. Erst als ich einen "normalen" ScriptManager verwendet habe, funktionierte das problemlos.
Auf dem Client wird nun eine Proxy-Klasse erstellt, die die Datentypen und die Methoden des Webservices in JavaScript nachgebildet werden. Darüber lässt sich der WebService sehr einfach aufrufen.
1: <script language="javascript" type="text/javascript"> 2: 3: function fnCallWebService() 4: { 5: ValuePlanner_2008.Services.INNProjectExplorerWebService.HelloWorld(5, fnHelloWorlSuccess, fnHelloWorlFailed); 6: } 7: 8: function fnHelloWorlSuccess(results, context, methodName) 9: { 10: alert(results.Text); 11: } 12: 13: function fnHelloWorlFailed(results, context, methodName) 14: { 15: alert ("Error calling webservice"); 16: } 17: </script>
in Zeile 5 wird der WebService mit der dem Namespace und dem Namen der Webservice Klasse aufgerufen. Zunächst wird der Parameter der HelloWorld-Methode übergeben. Da der Aufruf asynchron erfolgt kann wird noch eine Methode angegeben angegeb, die im Erfolgsfall aufgerufen wird, optional noch eine Methode, wenn der Aufruf fehlschlägt. In Zeile 10 sieht man schön, dass man in JavaScript nun auch das Datenobjekt des Rückgabewertes in gewohnter Weise zugreifen kann.
Eines der neuen coolen Features in VS2008 ist der Intellisense-Support und das einfärben für Javascript-Code. Das hat bei mir aber nicht funktioniert. Das Problem liegt daran, dass bei der Installation zwei Registry-keys nicht korrekt gesetzt werden.  Setzt man folgende Registry-Keys korrekt dann funktioniert das Intellisense einwandfrei: [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\CLSID\{014E9A41-54E5-44ED-B15E-EFFA8758BFFC}] "CodeBase"=file:///C:\\Program Files\\Microsoft Visual Studio 9.0\\Common7\\IDE\\Microsoft.JScript.AuthoringServices.dll [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\CLSID\{014E9A41-54E5-44ED-B15E-EFFA8758BFFC}\InprocServer32\9.0.0.0] "CodeBase"=file:///C:\\Program Files\\Microsoft Visual Studio 9.0\\Common7\\IDE\\Microsoft.JScript.AuthoringServices.dll Nähere Infos findet man hier.
Auf dieser Seite sind jede Menge Beispiele zum Thema LINQ thematisch geordnet aufgelistet. Hier findet man wirklich für viele Einsatzgebiete entsprechende Beispiele. Wirklich empfehlenswert! 101 LINQ Samples
Wenn man eine Datei löscht, die in der Quellcode-Verwaltung eingecheckt war, kann man diese leicht aus der Quellcode-Verwaltung wiederherstellen. Dazu muss man aber zuerst eine kleine Einstellung vornehmen. Unter Tools / Options / Source Control / Visual Studio Team Foundation Server kann man die Option "Show deleted items in the Source Control Explorer" aktivieren. Dann werden im Source Control Explorer gelöschte Elemente angezeugt, die man einfach "undeleten" kann. 
Wer mal etwas mehr mit WCF programmiert hat, wird feststellen, dass es recht müßig ist, für jeden Service einen Host zu implementieren. Deshalb habe ich zusammen mit meinem Kollegen Tobi einen WCF Service-Managerr entwickelt. Dieser Servicemanager wird auf dem Application-Server als Windows-Dienst ausgeführt und ist in der Lage Services die in DLLs bereitgestellt werden dynamisch zu laden und auszuführen. Zur Steuerung dient ein Client der natürlich per WCF mit dem Service-Manager kommuniziert. Damit kann auch eine größere Zahl von Services auf einem Application-Server effizient verwaltet werden.
Der Service-Manager kann inkl. einer kleinen Doku kostenlos heruntergeladen und verwendet werden. Über ein Feedback würde ich mich freuen. artisoServiceManager.zip (5,94 MB) Version 0.9.0
Während einer Präsentation hat man oft das Problem, dass man einen Bereich vergrößern möchte um ihn für das Publikum besser lesbar zu machen. Das kann man mit dem kleinen kostenlosen Tool ZoomIt ganz einfach bewerkstelligen. Zusätzlich bietet das Tool auch die Möglichkeit, dass man direkt auf dem Desktop Striche zeichnet. Dadurch kann man z.B. bestimmte Bereiche während der Präsentation kennzeichnen. Den Download gibt's hier
Preisfrage: Was passiert bei folgendem Code: Dictionary<int, string> Names = new Dictionary<int, string> { { 1, "Thomas" }, { 2, "Chris" } };
Names[5] = "Luka";
Ich hätte erwartet, dass der eine KeyNotFoundException wirft. Tut er aber nicht. Statt dessen wird einfach ein neues Element dem Dictionary hinzugefügt mit dem Key 5 und dem Value "Luka". Ob man das verwenden sollte sei mal dahingestellt, aber zumindest gut zu wissen.
Möchte man den kleinesten Key aus einem Dictionary abfragen, dann kann man das jetzt mit Hilfe von LINQ ganz einfach tun. Das Dictionary-Objekt ist in C#3.0 mit einer ensprechenden Extension versehen wordurch das Ganze so einfach ist, wie man sich das immer gewünscht hat.
Dictionary<int, double> ListObject = new Dictionary<int,double>
{
{2004, 1.5}, {2005, 2.7}, {2006, 3.8}
};
int minYear = ListObject.Min(l => l.Key);
Ich habe mich entschieden, von Zeit zu Zeit Kurzbeschreibungen zu Büchern, die ich aktuell lese zu posten. Vielleicht erhält der eine oder andere dadurch die Anregung, sich mit einem Buch näher zu beschäftigen. Ich poste hier meine ganz private Meinung und bekomme auch keine Provision dafür, wenn jemand das Buch kauft. Ich werde so objektiv wie möglich berichten, wie ich die Bücher einschätze.  | Den Anfang möchte ich mit einem Buch von Dino Esposito machen. In "ASP.Net AJAX Programmierung beschreibt Dino fundiert aber dennoch leicht verständlich, wie AJAX funktioniert, wie ASP.NET AJAX aufgebaut ist und wie das ASP.NET AJAX Component Toolkit eingesetzt werden kann.
Das Buch setzt entsprechende Kenntnisse in der Programmierung von ASP.NET und auch HTML und Javascript voraus und richtet sich damit an Entwickler die bisher bereits Web-Anwendungen mit ASP.NET entwickelt haben. Es bietet eine gute Grundlage für die Programmierung von AJAX Anwendungen und vermittelt auch die Hintergründe zur Technologie, so dass man bestimmte Probleme und Effekte besser verstehen kann. Dino bietet jede Menge Tipps, wie man mit ASP.NET AJAX seine Anwendungen aufbauen sollte und welche Fehler man vermeiden sollte. Damit ist das Buch eine wertvolle Unterstützung für alle die ihre ASP.NET Anwendungen mit Hilfe von AJAX optimieren wollen.
Die Beispiele sind nicht übermäßig ausführlich aber präzise beschrieben. Die oben Beschriebenen Grundkenntnisse vorausgesetzt kann man schnell folgen und vieles davon auch gleich in der Praxis einsetzen. Der Stil des Buches ist angenehm und gut lesbar, so dass ich dieses Buch auf jeden Fall empfehlen kann. | Microsoft ASP.NET AJAX-Programmierung von Dino Esposito erschienen bei Microsoft-Press
Vor kurzem hatte ich in einem Post beschrieben, wie man mit C#3.0 Listen effizient initialisieren kann. Das Ganze funktioniert übrigens auch mit Dictionaries. Das siehtr dann einfach so aus: productVersion.Sales = new Dictionary<int,double>
{
{2004, 1.5}, {2005, 2.7}, {2006, 3.8}
};
Ich hatte gerade ein kleines Problem mit der Object Test Bench. Die Object Test Bench ermöglicht es, im Visual Studio Instanzen von Objekten zu erzeugen, auf denen man dann direkt Methoden aufrufen kann, ohne die Anwendung zu starten. Dazu geht man in den Class View oder den Class Designer, klickt die entsprechende Klasse mit der rechten Maustaste an und ruft dann aus dem Kontext-Menü den Befehl "Create Instance" auf ... Tja, wenn der Befehl denn da wäre. Bei mir war da nichts zu sehen. Nach einigem Versuchen habe ich dann rausgefunden, dass dies wohl nur auf dem Projekt funktioniert, das als Startprojekt ausgewählt wurde. Also habe ich meine Library als Startprojekt gekennzeichnet und siehe da, es funktioniert. Schade ist allerdings, dass Methoden, die generische Datentypen zurückliefern nicht von der OTB unterstützt werden. Weiterführende Informationen findet man hier: http://blogs.msdn.com/parthopdas/archive/2005/05/04/414704.aspx
Objekte und Listen lassen sich jetzt in C# 3.0 sehr schön initialisieren. War bisher um ein relativ einfaches Objekt zu initialisieren sehr viel Code erforderlich, hat sich das nun deutlich verkürzt: Bisher: List<cProduct> Products = new List<cProduct>();
cProduct Product = new cProduct();
Product.ID = 1;
Product.BusinessDevelopmentComment = "";
Product.MarketingComments = "";
Product.VersionDescriptions = new List<cProductVersionDescription>();
Product.INNs = new List<cProductINNItem>();
cProductVersionDescription VersionDescription = new cProductVersionDescription();
VersionDescription.ID = 1;
VersionDescription.LastPCMDate = DateTime.Now;
VersionDescription.LastPCMDecision = "Go";
VersionDescription.NPV = 689.54;
VersionDescription.ProductID = 1;
VersionDescription.ProductVersionID = 1;
VersionDescription.VersionName = "Version1";
Product.VersionDescriptions.Add(VersionDescription);
cProductINNItem INN = new cProductINNItem();
INN.INN = 8;
INN.Dosage = 1.5;
INN.DosageUnit = 1;
INN.Volume = 1;
INN.Comment = "Test-Comment";
INN.INNOrder = 1;
Product.INNs.Add(INN);
INN = new cProductINNItem();
INN.INN = 2;
INN.Dosage = 2.5;
INN.DosageUnit = 2;
INN.Volume = 2;
INN.Comment = "Test-Comment2";
INN.INNOrder = 2;
Product.INNs.Add(INN);
Neu mit C#3.0:
List<cProduct> Products = new List<cProduct>
{
new cProduct{ ID = 1, BusinessDevelopmentComment = "", MarketingComments = "",
VersionDescriptions = new List<cProductVersionDescription>
{
new cProductVersionDescription{ ID=1, LastPCMDate=DateTime.Now, LastPCMDecision="Go", NPV=689.54, ProductID=1, ProductVersionID=1, VersionName="Version1"}
},
INNs = new List<cProductINNItem>
{
new cProductINNItem{ INN=8, Dosage=1.5, DosageUnit=1, Volume=1, Comment="Test-Comment", INNOrder=1},
new cProductINNItem{ INN=2, Dosage=2.5, DosageUnit=2, Volume=2, Comment="Test-Comment2", INNOrder=2}
}
}
};
Bisher konnte man den Code noch etwas vereinfachen, indem man einen entsprechenden Konstruktor für die Objekte erstellt hat, in dem die Initialisierungswerte übergeben werden konnten. Hier bietet die neue Version aber den Vorteil, dass diese leichter zu leesen ist, da die Parameter hier entsprechend bezeichnet sind. Beim Konstruktor musste immer Intellisense zu Hilfe genommen werden um herauszufinden, um welchen Parameter es sich handelt.
Möchte man ASP.Net Anwendungen mit VS2008 debuggen, dann ist entscheidend, welchen Servermode man in den Einstellungen für das Web-Projekt ausgewählt hat. Mit dem Visual Studio Developer Server hat das bei mir auf anhieb funktioniert. Allerdings mit dem IIs gab es Probleme. Hier habe ich zuerst diese NMeldung bekommen: Unable to start debugging on the web server. Strong name validation failed. Diesen Fehler kann man beheben indem man folgendes Procedere durchführt: - Visual Studio beenden!
- Den "Visual Studio Command Prompt" mit "Run as Administrator" starten.
- Dann folgenden Befehl ausführen: sn.exe -Vr "%ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE\iisresolver.dll"
Damit sollte diese Meldung behoben sein. Dann kam aber bei mir der nächste Fehler: Unable to start debugging on the web server. IIS does not list an application that matches the launched URL. Um diesen Fehler zu beseitigen muss man die Windows Authentification aktivieren. Dazu geht man folgendermaßen vor: - Im Explorer auf "Computer" Rechtsklick und dann "Manage"
- Den IIS Manager öffnen und die entsprechende Anwendung auswählen
- "Authentication" unter IIS doppelklicken und dann "Windows Athentication" auf Enabled setzen
Damit hat bei mir das Debuggen dann auch mit dem IIS funktioniert.
Ich habe in einer Anwendung ein Objekt, das über ca. 30 List<double> Properties verfügt. Dieses Objekt möchte ich nun mit LINQ to SQL in die Datenbank schreiben. Natürlich unterstützt LINQ 1:n-Beziehungen in Objekten aber in der Datenbank müsste ich dann für jedes List-Property eine eigene Tabelle anlegen und für jedes Property einen eigenen Typ definieren. Das schien mir doch sehr umständlich. Ich habe dann nach einer Möglichkeit gesucht, die List-Elemente etwas effizieter zu speichern, am einfachsten in einem Feld je Liste, da ich die für die Abfrage eh nicht brauche. Aber wie kann ich die Ausgabe von LINQ in die Datenbank steuern? Wie kann ich erreichen, dass LINQ meine Daten entsprechend formatiert? Googeln brachte keine vernünftigen Ergebnisse und sonst bin ich auch nicht fündig geworden, aber dann kam die Idee (manchmal ist es schneller erst nachzudenken bevor man googelt, aber das vergisst man oft ). Die Grundidee war, für jede Liste noch ein zusätzliches Property anlegen, das die Daten im Getter und Setter entsprechend formatiert. Die Hoffnung war, wenn ich dieses Property mit einem Column-Attribut versehe, wird LINQ den formatierten Inhalt schreiben und beim Lesen wieder zurückformatieren. public List<string> Sales { get; set; }
[Column(Name="Sales", DbType = "nvarchar(4000)")]
private string SalesString
{
get
{
return string.Join("|", Sales.ToArray());
}
set
{
if (value != null)
Sales = value.Split('|').ToList();
}
}
Ich habe einfach eine Text-Spalte in der Datenbank verwendet und die einzelnen List-Elemente mit einem Trennzeichen verbunden (der Einfachkeit halber habe ich mit einer List of Strings gearbeitet. Für die Tests ist das ausreichend und sollte auf beliebige andere Typen übertragbar sein).
Einen kleinen Stolperstein gibt es noch. Beim Ausführen erhielt ich folgende Meldung:

LINQ verwendet Optimistic Locking für das Schreiben und hat wohl Probleme, wenn der Inhalt des Property im Getter verändert wird. Abhilfe schafft hier das zusätzliche Attribut UpdateCheck, also sollte das Attribut zu dem Property so aussehen:
[Column(Name="Sales", DbType = "nvarchar(4000)", UpdateCheck=UpdateCheck.Never)]
Hier sind natürlich auch noch andere Möglichkeiten der Datenrepräsentation möglich. Hier mal ein Beispiel mit XML-Serialisierung und diesesmal auch mit Doubl-Werten.
public List<double> Sales { get; set; }
[Column(Name="Sales", DbType = "xml", UpdateCheck=UpdateCheck.Never)]
private string SalesString
{
get
{
UTF8Encoding encoding = new UTF8Encoding();
MemoryStream ms = new MemoryStream();
XmlSerializer xmlSer = new XmlSerializer(typeof(List<double>));
xmlSer.Serialize(ms, Sales);
return encoding.GetString(ms.ToArray());
}
set
{
if (value != null)
{
UTF8Encoding encoding = new UTF8Encoding();
MemoryStream ms = new MemoryStream(encoding.GetBytes(value));
XmlSerializer xmlSer = new XmlSerializer(typeof(List<double>));
Sales = (List<double>)xmlSer.Deserialize(ms);
}
}
}
Dank an Bernhard Gojer für den Lösungsansatz.
Vom 10.Oktober bis 12.Oktober findet in Berlin die XTOPIA statt. Dabei handelt es sich um eine Web-Konferenz von Microsoft, die sich an Entwickler, Entscheider und Designer richtet. Im Zentrum dabei steht Silverlight.
Ich werde auf der XTOPIA als ATE (Ask The Expert) zum Thema Visual Studio Team System vertreten sein.

Nutzt man LINQ in einer klassischen 2-tier Anwendung, dann funktioniert das wunderbar. Nur leider ist das eher ein Auslaufmodell. Bei modernen Anwendungen kommt häufig ein 3-tier Ansatz vor (SOA etc.). An einer kleinen WCF-Anwendung möchti ich das Problem kurz schildern: Eine kleine Anwendung soll Daten darstellen und bearbeiten können. nehmen wir einfach mal eine Adress-Verwaltung. Die Anwendung soll service-orientiert augebaut sein, d.h. es gibt einen zetralen Service, der die Schnittstelle zur Datenbank implementiert. Soll nun eine Liste der Adressen geladen werden, ruft der Client auf dem Service eine entsprechende Methode auf. Diese Methode nutzt nun LINQ um die Adressen aus der Datenbank zu lesen und als List<cAddress> zurückzuliefern. Diese kann der Client nun darstellen. So weit, so gut. Aber was passiert jetzt, wenn eine Adresse bearbeitet wird und diese wieder gespeichert werden soll. Der Client ruft eine entsprechende Methode auf dem Service auf und übergibt das neue Adress-Objekt. Durch die Übertragung zum Client und wieder zurück muss das Objekt serialisiert und wieder deserialisiert werden. Dadurch stellt es eine komplett andere Instanz dar, wenn es wieder beim Service ankommt und hat daher keine Verbindung mehr zum DataContext (vorausgesetzt dieser wäre überhaupt noch vorhanden, dazu müsste der in einer Session aufbewahrt werden, was recht problematisch ist). Wie bekommt man nun das neue Adress-Objekt in die Datenbank? Die von Microsoft vorgschlagene Vorgehensweise geht über die Attach-Methode. Dabei erzeugt man einfach einen neuen DataContext und fügt das bearbeitete Objekt diesem hinzu. Das Problem dabei ist das Change-Tracking des DataContext. Dieser möchte nämlich wissen, was sich an dem Objekt geändert hat. Führt man nur einen Attach durch, dann bewirkt das gar nichts. Man kann entweder das gesamte Objekt als bearbeitet deklarieren, so wie ich das in diesem Post demonstriert habe, oder man muss ein Referenz-Objekt mit angeben, gegen das das Objekt evrglichen werden kann. Eine weitere Möglichkeit ist auch noch die Zuweisung aller geänderten Eigenschaften nach dem Attach, da ab diesem Zeitpunkt das Change-Tracking alle Änderungen registriert. Das ist alles nicht so schön. Mit einem kleinen Trick kan man sich hier die Sache etwas einfacher machen, auch wenn das nicht gerade sauber ist. Man kann das Objekt einfach löschen und dann neu hinzufügen. Das angenehme ist, dass der DataContext das recht intelligent handhabt und intern aus dem Delete and Insert ein Update macht. Der Code sieht dann ungefähr so aus: public void UpdateCompany(LINQTest.Contracts.DataContracts.cContactCompany company)
{
cContactDataContext db = new cContactDataContext("Data Source=NOTEBOOK_VISTA;Initial Catalog=LINQ;Persist Security Info=True;");
cContactCompany OrigCompany = db.Companies.Single<cContactCompany>(c => c.ID == company.ID);
if (OrigCompany != null)
{
db.Companies.Remove(OrigCompany);
}
db.Companies.Add(company);
db.SubmitChanges();
}
Auch wenn das, wie gesagt nicht besonders schön ist, ich konnte noch keine negativen "Nebenwirkungen" feststellen, der Code macht genau das, was ich von ihm erwarte und das auch noch mit relativ schönem SQL, wie mir der SQL-Profiler anzeigt. Erst wird mal ein SELECT gemacht um zu sehen, ob das Element schon vorhanden ist (diesen Punkt kann man sicher noch optimieren):
exec sp_executesql N'SELECT [t0].[ID], [t0].[CompanyName], [t0].[CompanyAddress], [t0].[CompanyTelephone]
FROM [tblCompanies] AS [t0]
WHERE [t0].[ID] = @p0',N'@p0 int',@p0=2
Dann wird der Update ausgeführt
exec sp_executesql N'UPDATE [tblCompanies]
SET [CompanyName] = @p1
WHERE [ID] = @p0',N'@p0 int,@p1 nvarchar(12)',@p0=2,@p1=N'Test-Company'
Das sieht doch eigentlich sehr schön aus.
Problematisch wird die Sache nun, wenn das Objekt Unterelemente enthält, also z.B. Ansprechpartner. Hier gibt es mit dem Attach keine saubere Lösung undauch der Delete and Insert Ansatz versagt hier zunächst. Es wird einfach für alle untergeordneten Elemente ein Insert ausgeführt, egal ob diese bereits existieren oder nicht. Das Ganze kann man lösen, indem man auch die Unterelemente zunächst löscht.
public void UpdateCompany(LINQTest.Contracts.DataContracts.cContactCompany company)
{
cContactDataContext db = new cContactDataContext("Data Source=NOTEBOOK_VISTA;Initial Catalog=LINQ;Persist Security Info=True;User ID=sa;Password=admin");
cContactCompany OrigCompany = db.Companies.Single<cContactCompany>(c => c.ID == company.ID);
if (OrigCompany != null)
{
db.Companies.Remove(OrigCompany);
foreach (cContactPerson p in OrigCompany.Persons)
{
db.Persons.Remove(p);
}
}
db.Companies.Add(company);
db.SubmitChanges();
}
Auch hier wird wieder ein schönes Update daraus gebaut.
Also so richtig toll finde ich das Ganze noch nicht. Hier bleibt zu hoffen, dass Microsoft an dieser Stelle schnellstens noch nachbessert. Das sieht im Moment aber eher schlecht aus, wie man hier und hier lesen kann. Vielleicht hat schon jemand von euch hier Erfahrungen gesammelt. Über einen Kommentar würde ich mich freuen, auch über "Bedenken" bezgl. des Delete and Insert Ansatzes.
Ein Benkannter hatte gerade ein seltsames Problem. Unter VB.Net kann man sehr einfach einen Splash-Screen einrichten. Offensichtlich scheint es da allerdings ein Problem zusammen mit dem Virtual Server zu geben. Jedesmal wenn er die Anwendung innerhalb des Virtual Servers ausgeführt hat, wurde der Splash-Screen angezeigt und er erhielt dann eine Nullreference Exception. In der Host-Umgebung funktionierte das problemlos. Beidesmal kam Win2000 als Betriebssystem zum Einsatz. Hat schn mal jemand so ein Problem gehabt? Hier der Stacktrace: at System.Windows.Forms.Control.WaitForWaitHandle(WaitHandle waitHandle) at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous) at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args) at System.Windows.Forms.Control.Invoke(Delegate method) at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.HideSplashScreen() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.MainFormLoadingDone(Object sender, EventArgs e) at System.EventHandler.Invoke(Object sender, EventArgs e) at System.Windows.Forms.Form.OnLoad(EventArgs e) at System.Windows.Forms.Form.OnCreateControl() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) at System.Windows.Forms.Control.CreateControl() at System.Windows.Forms.Control.WmShowWindow(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ScrollableControl.WndProc(Message& m) at System.Windows.Forms.ContainerControl.WndProc(Message& m) at System.Windows.Forms.Form.WmShowWindow(Message& m) at System.Windows.Forms.Form.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.SafeNativeMethods.ShowWindow(HandleRef hWnd, Int32 nCmdShow) at System.Windows.Forms.Control.SetVisibleCore(Boolean value) at System.Windows.Forms.Form.SetVisibleCore(Boolean value) at System.Windows.Forms.Control.set_Visible(Boolean value) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(ApplicationContext context) at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine) at SplashScreen.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81 at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()
Ich habe gerade eben eine Seite, die ich mit VS 2008 und dem Framework 3.5 erstellt habe, auf einen Test-Server deployed. Alles hat wunderbar funktioniert, aber bei einer Seite bekam ich die Meldung, dass die Ressource nicht gefunden werden kann. Das konnte aber nicht sein, die Seite war da. Nach einigen Versuchen und einigem Wundern bin ich zufällig auf die Idee gekommen, mir mal den Source der Seite anzuzeigen. Und siehe da, hier steht nun endlich ein brauchbarar Hinweis. Im Source-Code war als Kommentar die Fehlermeldung versteckt. Der Grund war, dass eine Komponente auf ein verzeichnis zugreifen möchte, das auf dem Server nicht existiert. Ich habe versucht, den Fehler mit einer Test-Seite zu reproduzieren, aber erfolglos. Hat jemand eine Idee, woran das liegt und wie man das abstellen kann? Na jedenfalls wenn mal jemand ein ähnliches Problem hat, kennt er jetzt den Workaround. Nicht schön, aber es funktioniert. <html> <head> <title>Die Ressource kann nicht gefunden werden.</title> <style> ... </style> </head> <body bgcolor="white"> <span><H1>Serverfehler in der Anwendung /ValuePlanner_2008.<hr width=100% size=1 color=silver></H1> <h2> <i>Die Ressource kann nicht gefunden werden.</i> </h2></span> ... </body> </html> <!-- [DirectoryNotFoundException]: Ein Teil des Pfades c:\temp\text.txt konnte nicht gefunden werden. bei System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) bei System.IO.File.Delete(String path) ... --><!-- Diese Seite enthält möglicherweise vertrauliche Informationen, weil ASP.NET für die Anzeige ausführlicher Fehlermeldungen mit <customErrors mode="Off"/> konfiguriert ist. In Produktionsumgebungen sollten Sie <customErrors mode="On"/> oder <customErrors mode="RemoteOnly"/> verwenden.-->
Folgende Aufgabenstellung: In einem Infragistics WinGrid soll eine DataTable angezeigt werden. Am Ende des Grids soll eine TemplateAddRow, also eine leere Zeile zum Anlegen einer neuen Row angezeigt werden. Das Infragistics WinGrid unterstützt diese Funktion von Haus aus so, dass man in diese leere Zeile klicken kann und sobald man beginnt hier Werte einzutragen, dann wird in der DataSource tatsächlich eine neue Row angelegt und in dieser die Werte abgelegt. Gleichzeitig wird eine neue TemplateAddRow angelegt, mit der man wieder eine neue Zeile anlegen kann. Was aber nun, wenn man die Werte nicht im Grid selbst eingeben möchte, sondern in separaten Eingabefeldern? Dann geht man folgendermaßen vor: 1.) Zuerst erstellt man eine Form mit einer Bindingsource, einem Grid und diversen Eingabefeldern. Das Grid und die Eingabefelder werden an die BindingSource gebunden. 2.) Dann stellt man das Grid so ein, dass die TemplateAddRow angezeigt wird. this .ultraGrid1.DisplayLayout.Override.AllowAddNew = Infragistics.Win.UltraWinGrid.AllowAddNew.TemplateOnBottom; 2.) Damit nach dem neu Anlegen einer Zeile das Databinding auf den Eingabefeldern funktioniert muss nun manuell eine neue Zeile angelegt werden. Das Grid erzeugt diese Row in der DataSource erst wenn Werte eingegeben werden, das ist für unseren Fall zu spät. Deshalb nutzen wir das BeforeRowIndert Event. private void ultraGrid1_BeforeRowInsert(object sender, Infragistics.Win.UltraWinGrid.BeforeRowInsertEventArgs e) { this.myBindingSource.AddNew(); this.myBindingSource.Position++; e.Cancel = true; } 3.) Jetzt funktioniert bereits das erste Einfügen. Allerdings erscheint danach keine neue TemplateAddRow mehr. Hier muss man einen kleinen Trick anwenden: Man setzt die ActiveRow auf die TemplateAddRow. Dadurch wird eigentlich die TemplateAddRow nun in eine "echte Row" umgewandelt (was wir bereits ja zuvor manuell gemacht haben. Danach erstellt das Grid eine neue TemplateAddRow (das ist genau das was wir brauchen). Etwas unschön ist nun, dass die neue TemplateAddRow automatisch selektiert wird und wir damit schon wieder einen neuen Datensatz anlegen. Schöner wäre, wenn der gerade erzeugte Datensatz aktiv bleibt. Dazu merkt man sich einfach die aktive Row und setzt die danach wieder. Das Ganze habe ich auf einen Button gelegt, mit dem der Anwender die Eingabe abschließt. Alternativ kann natürlich auch ein anderes Event dafür verwendet werden. Sinnvoll ist hier sicher auch das BeforeSelectChange-Event des Grids entsprechend einzubinden. private void button1_Click(object sender, EventArgs e) { this.myBindingSource.EndEdit(); UltraGridRow temp = this.ultraGrid1.ActiveRow; this.ultraGrid1.ActiveRow = this.ultraGrid1.Rows.TemplateAddRow; this.ultraGrid1.ActiveRow = temp; }
Bin da gerade auf ein nettes Angebot gestoßen. SitePal bietet animierte Figuren, die man sich selber konfigurieren kann. Diese Figuren können dann Texte, die man vorgibt, sprechen, entweder aufgezeichnete Audio-Files oder auch über Texteingabe. Diese Figuren lassen sich dann in eine Web-Seite integrieren. Ist sicher interessant, wenn man ein entsprechendes Projekt hat. Mal sehen, vielleicht kann ich das zukünftig mal nutzen. SitePal Homepage
Bei der Neuinstallation eines Entwicklungsrechners dauert es immer ewig, bis man sich die ganzen nützlichen Helferlein zusammengesucht hat, die man im Laufe der Zeit zu schätzen gelernt hat. Deshalb habe ich mir gedacht, ich schreibe mir mal eine Liste, die ich dann immer wieder ergänzen kann. Und vielleicht ist für den einen oder anderen da auch noch was interessantes dabei. Also so könnte ein Entwicklungsrechner aussehen:
Betriebsystem / Standardanwendungen:
- Windows Vista Ultimate
- Office 2007
- SQL-Server 2005 Express
- SQL-Server 2005 Management Studio
Entwicklungsumgebung:
Tools
Stand 05.10.2007 To be continued...
Will man mit Visual Studio 2008 einem UserControl ein StyleSheet zuordnen, sieht das normalerweise so aus:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs"
Inherits="Controls.WebUserControl1" %>
<head>
<link href="../App_Themes/style.css" rel="stylesheet" type="text/css" />
</head>
<asp:Button ID="Button1" runat="server" Text="Button" /><asp:TextBox ID="TextBox1"
runat="server"></asp:TextBox>
Damit scheint aber der Designer von Visual Studio 2008 Beta 2 Probleme zu haben. Sowohl im Split-View als auch im Design-View wird nach einem Refresh nichts mehr angezeigt.

Bei mir hat hier ein kleiner Trick geholfen. Man verschiebt einfach das Link-Tag mit dem Stylesheet ganz an's Ende des Codes. Dann kann man mit Hilfe der Refresh-Funktion aus dem Kontext-Menü des Design-Panes die Anzeige aktualisieren und siehe da, Button und Textbox werden wieder angezeigt.

Ist eine ASP.Net Seite scrollbar, gibt es den unschönen Effekt, dass die Seite nach dem Postback wieder ganz oben steht. Ich habe mal eine kleine Beispiel-Seite, die diesen Effekt demonstriert:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="ValuePlanner_2008.Web.INN_ProjectArea.WebForm2" %> <%@ Register Assembly="cTextBox" Namespace="artiso_lib.UserControls" TagPrefix="cc1" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page </title> </head> <body> <form id="form1" runat="server"> <div> <% 1: for (int i = 0; i < 50; i++) 2: { 3: Response.Write(i + "<br>"); 4: } 5: %> </div> </form> </body> </html>
Dieses Problem kann man ganz einfach umgehen, indem man in der Page-Direktive das Attribut MaintainScrollPositionOnPostback="true" einfügt, also:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="ValuePlanner_2008.Web.INN_ProjectArea.WebForm2" MaintainScrollPositionOnPostback="true" %>
Im ASP.Net AJAX Toolkit findet man ein ModalPopup, das sehr gute Dienste leistet, will man Meldungen etwas eleganter ausgeben als mit einem schlichten alert(). Die Handhabung ist relativ einfach. Man nehme ein beliebiges Serverseitiges Control und weise diesem den ModalPopupExtender zu. Dann gibt man noch mindestens die ID des Controls an, das den Inhalt des Popups repräsentieren soll und fertig. Will man das Popup allerdings client-seitig per Java-Script aufrufen, muss man ein wenig in die Trickkiste greifen. Das Problem dabei ist, dass der ModalPopupExtender immer ein TargetControl braucht. Ich habe dafür einfach ein unsichtbares DIV erzeugt, das mit runat="server" auch auf dem Server sichtbar gemacht wurde. Dann kann man mit $Find('<ID des ModalPopupExtenders>').show() das Popup aufrufen.
Neu war an diesem Beispiel für mich auch der Style filter: alpha(opacity = 70) mit dem man eine Transparenz erzeugen kann.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="ValuePlanner_2008.Web.INN_ProjectArea.WebForm1" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
<style type="text/css">
.modalBackground
{
filter: alpha(opacity = 70);
background-color: #CCCCCC;
}
.ErrorMessage
{
background-color: #800000;
color: #FFFFFF;
}
</style>
</head>
<script language="javascript" type="text/javascript"> 1: 2: function okScript() 3: { 4: alert ("OK-Button wurde gedrückt"); 5: } </script>
<body>
<form id="form1" runat="server">
<div id="PopupPseudoPanel" style="display: none" runat="server">
</div>
<cc1:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</cc1:ToolkitScriptManager>
<cc1:ModalPopupExtender ID="ModalPopupExtender" runat="server" PopupControlID="Panel1"
DynamicServicePath="" Enabled="True" TargetControlID="PopupPseudoPanel" BackgroundCssClass="modalBackground"
OkControlID="OkButton" CancelControlID="CancelButton" OnOkScript="okScript();">
</cc1:ModalPopupExtender>
<br />
<br />
<input id="Button2" type="button" value="button" onclick="$find('ModalPopupExtender').show();" />
<asp:Panel ID="Panel1" runat="server" CssClass="ErrorMessage" style="display:none">
<h1>
Popup</h1>
<p>
Das ist ein Popup!</p>
<center>
<asp:Button ID="OkButton" runat="server" Text="OK"></asp:Button>
<asp:Button ID="CancelButton" runat="server" Text="Cancel"></asp:Button>
</center>
</asp:Panel>
</form>
</body>
</html>
Wie man an meinen letzten Posts sieht, beschäftige ich mich momentan sehr intensiv mit LINQ to SQL. Eine wichtige Lektion habe ich gerade eben gelernt. Folgende Ausgangssituation: Ich habe eine ASP.Net Anwendung. In einem DAL lese ich per LINQ ein Objekt aus der Datenbank und schreibe das dann in eine Session-Variable. Der Anwender bekommt das Objekt an der Oberfläche angezeigt und kann es verändern. Nun möchte ich das Objekt wieder in die Datenbank zurückschreiben. Fast alle Tutorials zu LINQ beschreiben, wie einfach es ist, Daten via LINQ zu schreiben. Aber dort wird in einer einzigen Funktion erst gelesen, dann werden die Daten verändert und dann wieder zurückgeschrieben. Das tritt ja aber in der Praxis eher selten auf. Also habe ich mich gefragt, was LINQ tut, wenn ich den DataContext einfach neu instanziere und dann einfach mein Objekt per Add an die Tabelle hinzufüge. Na ja,wie zu erwarten, hat LINQ gemeldet, dass der entsprechende Primary Key bereits existiert. Also was tun? Den gesamten DataContext in die Session legen? Dass das keine gute Idee ist, habe ich ziemlich schnell rausgefunden. Der DataContext skaliert sehr schlecht, da er ein eingebautes Change-Tracking, Identity Tracking und sonst noch ein paar Nettigkeiten hat, die sich aber in einer Web_Anwendung recht eklig verhalten können. Nach einigem Suchen bin ich dann drauf gekommen, dass es auch noch eine Attach-Methode gibt. Damit konnte ich mein Problem schön lösen. Das Ergebnis für das Schreiben sieht nun so aus: public void SaveProductVersion(cProductVersion _ProductVersion)
{
DataContext dataContextProducts = new DataContext("Data Source=NOTEBOOK_VISTA;Initial Catalog=ValuePlanner_2008;Integrated Security=True");
if (_ProductVersion.ID == 0)
{
dataContextProducts.GetTable<cProductVersion>().Add(_ProductVersion);
}
else
{
dataContextProducts.GetTable<cProductVersion>().Attach(_ProductVersion, true);
}
dataContextProducts.SubmitChanges();
}
Hier wird abgefragt, ob es eine neue Produktversion ist (ID == 0). Wenn ja, dann füge ich die per Add hinzu (die ID wird von LINQ automatisch vergeben). Bei einem bestehenden Projekt verwende ich die Attach-Methode. Ganz einfach, wenn mans weiss. Wichtig ist noch, dass alle Properties des Objektes das Attribut UpdateCheck=none benötigen.
Scott Mitchell hat 75 Tutorials zum Thema Data Access mit ASP.Net 2.0 geschrieben. Hier ist praktisch alles an Technologie beschrieben, was für die Programmierung von datenbankbasierten Webanwendungen mit ASP.Net 2.0 notwendig ist. Einzig LINQ wird momentan noch ausgespart. Eine wirklich tolle Sammlung an guten Informationen.
Data Access Tutorials : The Official Microsoft ASP.NET 2.0 Site
Wenn man mit LINQ to SQL arbeitet, dann steht man sehr schnell vor dem Problem, dass man sehen möchte, wass denn LINQ mit der Datenbank so treibt. Der SQL Profiler kann zwar die abgesetzten SQL-Statements anzeigen, die zurückgegebenen Ergebnisse muss mann dann aber von Hand abfragen. Viel eleganter geht es mit dem LINQ to SQL Debug Visualizer von Scott Guthrie. Damit kann man die Abfrage im Debug-Modus von Visual Studio 2008 einfach anzeigen lassen:   Mit dem Execute-Button kann man die Abfrage einfach ausführen und das Ergebnis anzeigen lassen.  Ein echt cooles Tool. Download und eine Installationsanleitung gibt es hier. LINQ to SQL Debug Visualizer - ScottGu's Blog
Ich habe folgendes Datenmodell mit dem LINQ To SQL Designer aufgebaut:
So, eigentlich ganz einfach. Mit folgendem Code kann ich die Daten einlesen: var formList = from f in listDataContext.cFormListItems
orderby f.FormShort
select f; var countryList = from c in listDataContext.cCountryListItems
orderby c.CountryName
select c;
Damit liest LINQ die Daten für die Forms bzw. die Countries ein, die zugeordneten Tabellen bleiben leer, bis man auf das entsprechende Element zugreift, dann wird das nachgeladen (lazy loading). Dieser Effekt ist super, wenn ich z.B. eine Liste der Kunden habe und den Kunden Bestellungen zugeordnet sind und ich teilweise Kunden mit mehreren tausend Bestellungen habe. Dann will ich die Bestellungen nicht gleich alle mitladen. Aber in meinem Fall war es so, dass in den verknüpften Tabellen nur wenige Datensätze stehen und ich deshalb lieber alles auf einen Rutsch laden wollte. Das geht dann so: listDataContext = new cListDataContext("Data Source=NOTEBOOK_VISTA;Initial Catalog=ValuePlanner_2008;Integrated Security=True");
// Define LoadOptions to load some related tables with their parent tables in one select statement
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<cFormListItem>(f => f.FormType);
loadOptions.LoadWith<cCountryListItem>(c => c.Market);
listDataContext.LoadOptions = loadOptions;
Diesen Code muss man vor der ersten Abfrage ausführen. Hier werden zwei LoadWith (jeweils für eine untergeordnete Tabelle) mit angegeben. Dies bewirkt, dass die untergeordneten Tabellen mit der jeweiligen Haupttabelle in einem einzigen SELECT Statement aus der Datenbank geladen werden! Ein paar Sachen muss man allerdings beachten:
- Die LoadOptions können nur vor der ersten Abfrage auf dem DataContext zugewiesen werden.
- Die Loadoptions können nicht mehr verändert werden, wenn sie einmal einem DataContext zugewiesen wurden.
- Für mehrere Tabellen ruft man das LoadWith einfach mehrfach auf.
Ich hätte das zwar schöner gefunden, wenn man das auch mit im Designer einstellen könnte, aber es funktioniert einwandfrei.
Hier noch als Beweis das SQL-Statement, das dann tatsächlich auf der Datenbank ausgeführt wird:
SELECT [t0].[ID], [t0].[FormLong], [t0].[FormShort], [t0].[FormTypeID], [t1].[ID] AS [ID2], [t1].[FormTypeLong], [t1].[FormTypeShort]
FROM [values_Forms] AS [t0]
INNER JOIN [values_FormTypes] AS [t1] ON [t1].[ID] = [t0].[FormTypeID]
ORDER BY [t0].[FormShort]
Die Arbeitsbereiche des Team Foundation Server stellen eine Verknüpfung eines lokalen Verzeichnisses mit einem Pfad in der Quellcode-Verwaltung her. Aus verständlichen Gründen kann ein und das selbe Verzeichnis nicht mehrfach zugeordnet werden. Dies gilt insbesondere für den Fall, dass zwei verschiedene Benutzer auf dem gleichen Rechner das selbe Verzeichnis zuordnen wollen, auch wenn es sich auf den gleichen Pfad in der Quellcode-Verwaltung bezieht. Das ganze macht Sinn. Aber was tun, wenn z.B. der Benutzer A nicht mehr existiert und nun Benutzer B seine Projekte übernehmen soll? Der Rat lautet hier, von Benutzer A alle Arbeitsbereiche löschen, bevor der Benutzer gelöscht wird. Der Rat hilft aber wenig, wenn der Benutzer bereits gelöscht wurde und man dann erst die Probleme feststellt. Oder wenn, wie in meinem Fall, durch einen Umzug auf einen anderen Server der Benutzer neu angelegt wurde und zwar den gleichen Namen hat, aber eine andere SID. Die Anpassung der SIDs in der TFS-Datenbank scheint hier nicht richtig funktioniert zu haben.
Den lokalen Workspace zu löschen ist kein Problem, aber das hilft leider in diesem Fall nicht. Die Arbeitsbereiche sind auch zusätzlich noch auf dem Server gespeichert und dort muss man diesen nun löschen, damit man den mit dem neuen Benutzer neu einrichten kann.
Zunächst der Befehl, mit dem man die Workspaces vom Server anzeigen kann:
tf workspaces /owner:* /server:<TFS-Servername> /format:detailed
Um einen Workspace zu löschen kann nun folgender Befehl verwendet werden:
tf workspace /delete <Workspace-Name>;<Benutzername> /server:<TFS-Servername>
Es gibt auch noch den Befehl /updateUserName, der hat in meinem Fall aber leider nicht funktioniert.
Will man in einem Infragistics WebGrid ein Control in einer Zelle einer TemplatedColumn ansprechen, dann ist das gar nicht so einfach wie zunächst vermutet. Man muss ein paar Umwege einlegen. So funktionierts aber dann: protected void UltraWebGrid1_InitializeRow(object sender, Infragistics.WebUI.UltraWebGrid.RowEventArgs e) { DropDownList ddlUnit = ((DropDownList)((CellItem)((TemplatedColumn)e.Row.Cells.FromKey("Unit").Column).CellItems[e.Row.Index]).Controls[1]); .... } Statt dem Controls[1] könnte man auch noch ein FindControl() nutzen, das wäre noch etwas eleganter.
Scott Gutherie hat in seinem Blog eine interessante Artikel-Serie zu LINQ to SQL Data Access Improvements with LINQ to SQL LINQ to SQL is a built-in OR/M (object relational mapper) in .NET 3.5. It enables you to model relational databases using a .NET object model. You can then query the database using LINQ, as well as update/insert/delete data from it. LINQ to SQL fully supports transactions, views, and stored procedures. It also provides an easy way to integrate business logic and validation rules into your data model. Below are some of the articles I've written that explore how to use it: I'll be adding several more articles to my series above in the weeks ahead. I think you'll find that LINQ to SQL makes it dramatically easier to build much cleaner data models, and write much cleaner data code.
Die Beta 2 des Visual Studio 2008 (Oracs) sowie des Visual Studio 2008 Team Foundation Server Beta 2 sind jetzt verfügbar. Visual Studio 2008 Downloads
Unter C# einen Splash-Screen zu erzeugen ist immer etwas Arbeit. Dirk Hammann hat eine kleine Komponente erstellt, die das erledigt. Die Komponente ist Freeware und auch als Quellcode verfügbar. SplashDialog
Auf knapp 200 Seiten haben Kai Gloth und Norbert Eder viele Tipps und Tricks zusammengafasst und diese als PDF-Datei kostenlos bereitgestellt. .NET Casts - dotnetblogbook
Hat man ein typisiertes DataSet und arbeitet darin mit mehreren TableAdaptern, dann stellt sich die Frage, wie Updates auf diesen TableAdaptern in eine Transaktion zusammengefasst werden können. Das Problem dabei ist, dass jeder TableAdapter seine eigene Connection nutzt. Es gibt grundsätzlich zwei Lösungsansätze:
- Man verwendet den TransactionScope aus dem System.Transactions-Namespace. Diese Vorgehensweise hat allerdings den Nachteil, dass die verschiedenen Connections nur über eine Distributed Transactions verwaltet werden können. Das ist nicht unbedingt das Nonplusultra was die Performance angeht und eigentlich ja auch mit Kanonen auf Spatzen geschossen, da typischerweise alle TableAdapter ja auf die gleiche Datenbank gehen dürften und damit die Ditributed Transactions etwas überkandidelt sind.
- Man verwendet eine Connection für alle TableAdpater. Hierzu gibt es glücklicherweise die Möglichkiet, dass man die Connection der Tableadapter austauschen kann. Man kann z.B. einfach die Connection des ersten TableAdapters allen anderen zuweisen und dann auf dieser Connection mit BeginTransaction eine neue Transaktion beginnen und diese dann mit Commit bzw. RollBack abschließen. Alternativ kann man natürlich auch manuell eine Connection erzeugen und diese dann allen TableAdaptern zuweisen.
Eine sehr schöne Beschreibung dieser Lösungsansätze hat John Waters unter folgendem Link veröffentlicht: ADO.NET : Getting TableAdapters to participate in transactions
Wenn der Team-Explorer behauptet, einen nicht mehr zu kennen und mit folgender Meldung behauptet, man stellt keine bekannte Identität dar,

dann kann dieses Problem behoben werden, indem man den Cache des Team-Explorers löscht. Dieser liegt unter Vista im Ordner C:\Users\Thomas\AppData\Local\Microsoft\Team Foundation\1.0\Cache. Hier einfach alle Unterordner löschen und schon klappts wieder mit dem TFS.
 | Marco Hagenschulte, Betreiber von www.wsus.de, hat das Gewinnspiel „Tools für WSUS 3.0“ gestartet. Gesucht wird ein nützliches selbst-entwickeltes Werkzeug für die Windows Server Update Services 3.0 (Add-On, Sidebar Gadget, Scripts, usw.). Zum Gewinnspiel |
Habe gerade den ersten Praxis-Test mit Microsoft SharedView absolviert. Das hat auf Anhieb geklappt, echt klasse.
Das Tool erlaubt es, dass man eine Session einrichtet und die Teilnehmer der Session untereinander ihre Desktops oder auch nur einzelne Anwendungen freigeben können. Dabei können die anderen entweder nur zuschauen oder auch aktiv eingreifen. Das tolle dabei ist, dass für alle Teilnehmer eine einfache Internet-Verbindung genügt, auch für den Session-Initiator.
Ich wollte gerade einen externen Kollegen bei einer Fehlersuche unterstützen. Am Telefon war das aber kaum zu erklären. Wir haben einfach beide SharedView runtergeladen und installiert. Die Verbindung hat auf Anhieb geklappt, obwohl wir beide hinter einer Firewall sitzen. ich konnte mich auf seinen Desktop schalten und diesen bedienen. Das Ganze ist noch nicht sehr schnell, aber es handelt sich dabei ja noch um eine Beta-Version und hoffentlich wird das Release in Punkto Performance noch etwas zulegen. Das einzige, was am Anfang zu etwas Verwirrung geführt hat, war, dass der Kollege mir zwar die Kontrolle über seinen Desktop übertragen hat, die dann aber immer gleich wieder zurücksprang. Wir haben dann aber schnell rausgefunden, dass die Kontrolle wieder zurückgeht, wenn am Freigabe-Rechner die Maus bewegt wird. Wenn man's weiss, eigentlich gar nicht so schlecht.
Ich fand das Ding echt superklasse und wir konnten den Fehler recht schnell beheben. (Sicher schneller als per Telefon und auch schneller als wenn wir erst den remote desktop auf der Firewall hätten freischalten lassen müssen)
Microsoft SharedView Beta
Microsoft Surface ist eine neue revolutionäre Oberfläche, ein Tisch, ein Display, alles in einem und von allem etwas. Jedenfalls ist Microsoft Surface eine gigantische neue Möglichkeit, mit dem Computer zu interagieren, ohne Tastatur, ohne Maus. Ich hoffe, das Ding wird bald auch in Deutschland irgendwo zu bestaunen sein. Es lohnt sich, schon mal einen Blick auf die schöne neue Welt von morgen zu werfen. Microsoft Surface
Regionerate ist ein kleines Tool mit dem sich automatisch verschiedene Code-Elemente wie Properties, Methoden, Konstruktoren in separate Regions zusammenfassen lassen. Die entsprechenden Codezeilen werden dabei automatisch in bereits existierende Regions verschoben und hier sortiert. Die Regeln für die Gruppierung lassen sich anpassen. Ein kleiner Screencast zeigt, was das Tool alles kann. Damit entfällt nun endlich das lästige manuelle Sortieren der Felder und Properties. Regionerate Gefunden bei Dani Meier
Die nächsten Termine der .net Developer-Group Ulm sind: 02.08.2007 - 18:00 Uhr Thema: LINQ – Language Integrated Query 05.09.2007 - 18:00 Uhr Thema: Windows Workflow Foundation in ASP.NET Nähere Details unter www.dotnet-ulm.de
Ich werde in nächster Zeit bei einigen Usergroups unterwegs sein und einen Vortrag zum Thema Team Foundation Server halten. Die Termine sind momentan: 24.07.07 .net Developers Group München 25.09.07 bonn-to-code.net 01.10.07 .Net Usergroup Leipzig 31.10.07 .Net Developers Group Stuttgart Thema: Team Foundation Server in der Praxis Mit Team Foundation Server bietet Microsoft zusammen mit Visual Studio Team System ein leistungsfähiges System zur Organisation des gesamten Software Lifecycles. Die Key-Features sind: -
Verwaltung von Funktionsanforderungen, Aufgaben und Fehlern -
Quellcode-Verwaltung und Branching-Strategien -
Buildmanagement -
Überwachung von Projektmetriken und Reporting Wie diese Funktionen in der Praxis genutzt werden können und ob dies auch von kleinere Teams sinnvoll eingesetzt werden können, beleuchtet dieser Vortrag. Darüber hinaus werden einige Beispielszenarien aus der Praxis live vorgeführt. Weitere Termine sind in Vorbereitung. Wer noch Interesse an einem Vortragstermin hat, kann sich gerne an mich wenden.
Markus Alt hat in seinem Blog einen Link zu einem Whitepaper, das die Umsetzung eines Entwicklungsprozesses nach dem V-Modell XT mit Hilfe des Team Foundation Servers beschreibt. Das Dokument ist als PDF und als MSDN-Artikel verfügbar.
Ich nutze von meinem Notebook eine VPN-Verbindung über WLAN. Dabei habe ich immer wieder das Problem, dass die VPN-Verbindung behauptet, ich brauche zuerst eine Internet-Verbindung um die VPN-Verbindung nutzen zu können obwohl die Internet-Verbindung steht.
Inzwischen habe ich rausgefunden, dass das an den Virtal Ethernet Adapter liegt, die VMware auf meinem Rechner installiert haben. Wenn ich diese Adapter disable, dann funktioniert die VPN-Verbindung auf Anhieb.
In Excel kann man ein Textfeld anlegen und diesem einen variablen Inhalt geben. Hierzu markiert man das Textfeld und gibt in der Formelzeile z.B. einen Verweis auf eine Zelle ein (=A1). In A1 kann nun eine beliebige Formel stehen, z.B. ="Summe: " & SUMME(A2:A20). Möchte man in den text einen Zeilenumbruch einfügen, dann kann man die Funktion ZEICHEN(10) verwenden, also z.B. = "Summe 2006: " & SUMME(A2:A20) & ZEICHEN(10) & "Summe 2007: " & SUMME(B2:B20)

Seit Anfang Mai bin ich nun CLIP-Mitglied. Leider bin ich im Moment derart im Stress, dass ich erst jetzt dazu komme das hier zu bloggen. Leider leidet unter meiner aktuellen Arbeitsbelastung auch mein Blog, den ich momentan sehr vernachlässige, aber das wird sich hoffentlich bald wieder ändern.
http://www.microsoft.com/germany/community/programme/clip.mspx
Gerade hatte ich mal mit den Settings für Winform-Anwendungen etwas rumgespielt und bin dabei darauf gestoßen dass man auch für Klassenbibliotheken eine Settings-Datei anlegen und darin Werte erfassen kann. Die Frage war nun, wie kann ich diese Werte einstellen, wenn ich die Klassenbibliothek in eine Anwendung integriere? Nach einigem Googeln und Testen hier nun meine Ergebnisse:
- Die Konfiguration der Anwendung inkl. aller Klassenbibliotheken werden über eine zentrale konfigurationsdatei (app.config bzw. <Anwendungsname>.exe.config) vorgenommen.
- Die Konfigurationsparameter der Klassenbibliothek werden in diese zentrale Konfigurationsdatei leider nicht automatisch übertragen.
- Werden keine Konfigurationsparameter für die Klassenbibliothek angegeben, behält diese ihre Default-Werte (das sind die, die beim Kompilieren in der app.config der Klassenbibliothek standen). Diese Default-Werte sind in der Settings.Designer.cs hinterlegt und werden in die DLL reinkompiliert.
- Man kann diese Default-Werte übersteuern, indem man in der app.config der Anwendung einen zusätzlichen Settings-Block einfügt (im unteren Beispiel der Bereich ClassLibrary1.Properties.Settings). Diesen kopiert man am besten aus der app.config der Klassenbibliothek. Wichtig ist, dass dieser neue Block noch registriert wird. Dies passiert im Bereich <configSections> mit der Zeile.
<section name="ClassLibrary1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
Sonst erhält man eine Exception, dass die Configuration ungültig ist.
Nun kann man aus der Anwendung heraus auch die Parameter der Klassenbibliothek einstellen. Ich habe das z.B. verwendet um mir die Übergabe von Konfigurationsparametern an die Klassenbibliothek zu ersparen.
Was mir allerdings nicht besonders gut gefällt, ist die Tatsache, dass ich beim hinzufügen von neuen Config-Parametern für die Klassenbibliothek immer daran denken muss, auch in der Anwendung diese hinzuzufügen. Vergesse ich das, erhalte ich zwar keinen Fehler aber es wird einfach mit dem Default-Wert gearbeitet. Das kann manchmal durchaus erwünscht sein, in anderen Fällen ist das aber eher problematisch.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="WindowsApplication1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> <section name="ClassLibrary1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </sectionGroup> </configSections> <applicationSettings> <WindowsApplication1.Properties.Settings> <setting name="Setting" serializeAs="String"> <value>abc</value> </setting> </WindowsApplication1.Properties.Settings> <ClassLibrary1.Properties.Settings> <setting name="Setting" serializeAs="String"> <value>zzzz</value> </setting> </ClassLibrary1.Properties.Settings> </applicationSettings> </configuration>
Wird ein Connection-String in der config-Datei abgelegt, sollte man darin das Kennwort verschlüsseln. Der Connection-String sieht dann ungefähr so aus:
Data Source=MeinServer;Persist Security Info=True;User ID=User1;Password=vM17E6mtBos=;Unicode=True
Wenn man den Connection-String nun verwenden möchte, muss man darin das Passort erst einmal finden, entschlüsseln und dann im Connection-String das verschlüsselte Kennwort mit dem entschlüsselten ersetzen. Zum Entschlüsseln habe ich eine kleine Funktion eingesetzt, die einfach die Funktionen aus dem System.Security.Cryptography-Namespace verwendet. Das Suchen des Passworts mache ich dann mit einem RegEx:
private string Decrypt(string _connectionString) { Regex r = new Regex(@"^.*?Password=(?<Password>[^;]*)(;|$)", RegexOptions.IgnoreCase); string encrypted = r.Match(_connectionString).Groups["Password"].Value; string decrypted = Decrypt(encrypted, key); return _connectionString.Replace(encrypted, decrypted); }
Nachtrag:
OK, OK, auf dieses Post habe ich zum ersten mal seit ich blogge Kommentare bekommen und das gleich dutzendweise. Leider funktioniert die Bestätigungsfunktion für die Kommentare bei meinem Blog momentan nicht, da muss ich mal schauen.
Die meisten Kommentare bezogen sich darauf, dass man die config-Datei ja auch mit .net Bordmitteln einfach verschlüsseln kann. In meinem Fall war aber der Wunsch im Vordergrund, dass nur das Kennwort verschlüsselt werden sollte. Der Server sollte im ConnectionString frei editierbar sein. Und das ist meines Wissens nach mit den Standardmethoden nicht möglich. Gut, das hätte ich vielleicht im Post etwas klarer rausstellen sollen, aber...
Trotzdem hier als Ergänzung ein paar Links, die aus den Kommentaren, die das Thema Verschlüsselung der config-Datei beschreiben.
http://www.primetime-software.de/rouven.haban/PermaLink,guid,603e3d04-c67e-4837-9f9b-bc9fc3a15b9c.aspx
http://aspnet.4guysfromrolla.com/articles/021506-1.aspx
Hoffe damit sind nun alle zufrieden. Eigentlich ist es schon erstaunlich, dass man auf einen "schlechten" Post Antworten ohne Ende bekommt, auf die normalen oder vielleicht den einen oder anderen guten tut sich da gar nichts. Na ja, vielleicht überlege ich mir einfach in Zukunft hin und wieder Murks zu schreiben, ist doch recht interessant zu sehen, wer so alles meine Posts liest.
Mit der statischen Codeanalyse in VS kann der Quellcode nach verschiedenen Regeln analysiert werden. Es lassen sich auch eigene Regeln erstellen. Beginnt man damit zu arbeiten, ergibt sich die Frage, wie kann man die benutzerdefinierten Regeln und die Einstellung, welche Regeln verwendet werden sollen auf mehrere Projekte und für mehrere Entwickler anwenden.
Dazu ein paar Überlegungen:
1.) Benutzerdefinierte Regeln können durch Kopieren der entsprechenden DLL-Dateien auf die einzelnen Rechner verteilt werden. Dies kann z.B. über das Login-Script erledigt werden.
2.) Die Einstellungen welche Regeln aktiviert sind, sind im Projekt hinterlegt. Über die Quellcodeverwaltung nutzen somit alle Entwickler, die das Projekt bearbeiten, die gleiche Einstellung.
3.) Um die Einstellungen für neue Projekte zu übernehmen bietet sich die Erstellung einer entsprechenden Projektvorlage an, in der die entsprechenden Einstellungen vorgenommen werden. Wird ein neues Projekt auf dieser Vorlage erstellt, so erbt dieses die Einstellungen aus der Vorlage.
Gruppierungen in Excel sind eine feine Sache. Möchte man allerdings untenstehendes Beispiel gruppieren, ergibt sich ein Problem.
Die Gruppenzeile soll in diesem Fall oben stehen. Standardmäßig geht Excel aber davon aus, dass die unterste Zeile einer Gruppe bei einer eingeklappten Gruppierung übrig bleibt. Damit sieht dann das Resultat in dem Beispiel so aus, dass die Gruppe gar nicht mehr angezeigt wird:
Es gibt eine Möglichkeit, dies über eine Einstellung zu ändern. In Excel 2003 findet man die Menü Daten / Gruppierung und Gliederung / Einstellungen. In Excel 2007 ist die Einstellung etwas versteckt. Unter Data befindet sich im Bereich Outline rechts unten ein kleines Kästchen.

Klickt man darauf, dann öffnet sich ein Fenster, in dem man nun die Option Summary rows below detail abwählen kann.
Damit kann man die Gruppierung nun wie gewünscht einstellen.
Noch ein kleiner Tipp: Mit Shift + Alt + Pfeil rechts kann man die Gruppierung auch per Tastatur für die aktuell markierten Zeilen einstellen. Shift + Alt + Pfeil links hebt die entsprechende Gruppierung auf.
Das PropertyGrid ist ein sehr hilfreiches Control, mit dem man einfach die Inhalte der Properties einer Klasse an der Oberfläche anzeigen und bearbeiten kann. Ich hatte hierzu schon zwei Posts : Verwendung des Property-Grids, Dateien und Ordner im Property-Grid auswählen
Das Property-Grid stößt allerdings an seine Grenzen, wenn man damit mehrsprachige Umgebungen unterstützen möchte. Die Anzeige im PropertyGrid ist immer direkt vom Namen der Properties abgeleitet und die Description etc. wird über Attribute angegeben, die nicht über Ressource-Files lokalisiert werden können.
Auf Code-Project habe ich ein erweitertes Property-Grid gefunden, das genau dieses Problem beseitigt.
Link to PropertyGrid utilities - The Code Project - C# Programming
Danke an Chris für den Link!
Vor allem wenn man mit Services programmiert, hat man oft die Anforderung, dass beim Debuggen mehrere Projekte innerhalb der Solution gestartet werden müssen, z.B. ein Service und ein entsprechender Client. Der manuelle Weg war hier, dass man den Service als Startup-Projekt eingertragen hat, das debuggen startet und dann auf den Client im Solution Explorer mit der rechten Maustaste klickt und dann hier Debug / Start new Instance auswählt. Es gibt aber auch noch eine elegantere Möglichkeit. Auf der Eigenschaftsseite der Solution (rechte Maustaste / Properties) kann man unter Startup Project auch die Option Multiple startup projects wählen. Hier kann man nun bei mehreren Projekten die Action auf Start bzw. Start without debugging einstellen. Sogar die Startreihenfolge der einzlnen Projekte lässt sich definieren. Damit starten nun die eingestellten Anwendungen auf einmal.
Will man eine Liste nach XML serialisieren, die über ein Interface definiert ist, dann funktioniert das nicht. Es bleibt hier wohl nur die Möglichkeit, einen eigenen Serialisierer zu schreiben. In meinem Fall konnte ich das umgehen, indem ich auf das Interface verzichtet habe. Sollte jemand hier eine gute Idee haben, dann wäre ich für ein kurzes Feedback dankbar um das zukünftig zu berücksichtigen. Im Moment heißt das für mich, dass beim Serialisieren Interfaces tabu sind.
Ein Beispiel für eine nicht serialisierbare Liste ist z.B.
List<IMyInterface>
Bei der Dotnet Usergroup Bremen wurde das Thema in einem kleinen Artikel ausführlich diskutiert. Link to DOTnet Usergroup Bremen Danke an Chris für den Link
Eine umfangreiche Sammlung von Videos für die Entwicklung mit ASP.Net finden sich unter dem unten stehenden Link. Dabei wird ein weites Themenfeld abgedeckt. Vom Umstieg von ASP.Net 1.1 auf ASP.Net 2.0, Einstieg in ASP.Net 2.0, ASP.Net AJAX und auch zuküftige Themen wie LINQ, BLINQ etc. Link to ASP.NET-Videos für jeden Entwickler
Will man die Kalenderwoche zu einem Datum herausfinden, dann kann man die Funktion GetWeekOfYear nutzen.
CalendarRow.Week = Application.CurrentCulture.Calendar.GetWeekOfYear(CurrentDate, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
Diese Funktion hat allerdings einen kleinen Bug. So wird beispielsweise für den 31.12.2007 KW 53 zurückgegeben. Der darauffolgende Tag, ein Dienstag, ist dann allerdings in KW 1. Eigentlich müssten die Tage einer Woche aber immer in der selben KW sein. Abhilfe schafft hier eine kleine Korrektur. Wir haben ja eingestellt, dass unsere Woche am Montag beginnen soll (DayOfWeek.Monday) und dass die Woche immer dann als KW 1 betrachtet werden soll, wenn wenigstens 4 Tage davon im neuen Jahr liegen (System.Globalization.CalendarWeekRule.FirstFourDayWeek). Der Trick ist nun, dass man einfach immer 3 Tage hinzuzählt, wenn das gesuchte Datum zwischen Montag und Mittwoch liegt. Damit wird aus dem Montag Donnerstag, aus Dienstag der Freitag und aus dem Mittwoch ein Samstag. Da der Donnerstag der Tag ist, von dem abhängt, ob die Woche im neuen oder im alten Jahr liegt, haben wir Montag bis Mittwoch einfach nach hinten geschoben, so dass diese auf jeden Fall im neuen Jahr liegen und damit auch korrekterweise die KW 1 ergeben.
CalendarRow.Week = Application.CurrentCulture.Calendar.GetWeekOfYear(CurrentDate.DayOfWeek >= DayOfWeek.Monday && CurrentDate.DayOfWeek <= DayOfWeek.Wednesday?CurrentDate.Add(new TimeSpan(3,0,0,0)):CurrentDate, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
Mit diesem kleinen Plugin kann man Code-Ausschnitte direkt aus VS mit dem Windows Live Writer bloggen. Das Plugin übernimmt dabei die komplette Formatierung. Die Farbcodierung von VS bleibt dabei erhalten. Link to BlogMyCode VS2005 plugin
Ralf Westphal war am 20.03 in Ulm. Von 10:00 bis 17:00 konnten ihn in einer Kaffeehaus-Konsultation Entwickler mit Fragen löchern. Das Angebot wurde rege angenommen.
Sogar die regionale Presse hat über das Ereignis berichtet.
Danach hielt Ralf im Rahmen des Treffens der .net Developer-Group Ulm einen Vortrag zur Komponentenorientierung in der Software-Entwicklung.

 George Shepherd hat eine Vielzahl von wirklich guten Tipps & Tricks zur Windows- und Web-Programmierung in zwei FAQ-Listen zusammengetragen. Wirklich ein Quell von Anregungen, Problemlösern und Tipps & Tricks. Nicht nur zum Nachschlagen, sondern auch mal zum durchlesen empfohlen. Link zu Windows Forms FAQ Link zu ASP.NET FAQ
Um den Inhalt einer DataRow in eine andere DataRow zu kopieren kann einfach folgende Anweisung verwendet werden:
newRow.ItemArray = ( object[])copyRow.ItemArray.Clone();
Am 20. März ist Ralf in Ulm, um eine seiner berühmten Kaffehauskonsultationen im Cafe Bellavista zu geben. Wer sich also schon immer mal mit einem ausgewiesenen Experten in Sachen .net über ein Problem oder eine Idee unterhalten wollte, der kann jetzt die Gelegenheit nutzen - kostenlos! In der entspannten Umgebung eines Cafes lässt sich über vieles angenehmer diskutieren als auf Konferenzen oder sonstigen Veranstaltungen. Interessenten sollten sich unbedingt vorher bei Ralf per Mail anmelden.  Link to One Man Think Tank Gedanken: Kaffeehauskonsultation in Ulm
Das PropertyGrid ist ein sehr hilfreiches Control, mit dem man einfach die Inhalte der Properties einer Klasse an der Oberfläche anzeigen und bearbeiten kann. Ich hatte hierzu schon zwei Posts : Verwendung des Property-Grids, Dateien und Ordner im Property-Grid auswählen
Das Property-Grid stößt allerdings an seine Grenzen, wenn man damit mehrsprachige Umgebungen unterstützen möchte. Die Anzeige im PropertyGrid ist immer direkt vom Namen der Properties abgeleitet und die Description etc. wird über Attribute angegeben, die nicht über Ressource-Files lokalisiert werden können.
Auf Code-Project habe ich ein erweitertes Property-Grid gefunden, das genau dieses Problem beseitigt.

Link to PropertyGrid utilities - The Code Project - C# Programming
Danke an Chris für den Link!
In dem folgenden Beispiel wird aus einer Auflistung der Typ der Elemente ermittelt und anschließend eine neue Instanz dieses Typs angelegt. Dann werden die Properties die über DisplayMember und ValueMember übergeben wurden mit Werten befüllt. Damit kann die Liste ergänzt werden, ohne Zugriff auf den Datentyp zu haben. Einzige Voraussetzung ist, dass in der DataSource bereits Elemente vorhanden sind.
foreach (cListEntry item in Items) { Type t = ((IList)dataSource)[0].GetType(); object o = Activator.CreateInstance(t); if (this.DisplayMember!= null && this.DisplayMember!= "") t.GetProperty(this.DisplayMember).SetValue(o, item.Text, null); if (this.ValueMember!= null && this.ValueMember!= "") t.GetProperty(this.ValueMember).SetValue(o, item.Value, null); }
Nachtrag:
Wenn der Typ, von dem eine neue Instanz erzeugt werden soll, keinen parameterlosen Konstruktor hat, funktioniert das obige Beispiel nicht. Abhilfe kann man hier schaffen, indem man einen parameterlosen Konstruktor anlegt und diesen als private deklariert. Dadurch kann ich beim Instanzieren weiterhin sicherstellen, dass Pflichtangaben gemacht werden, weil der parameterlose Konstruktor ja nicht sichtbar ist.
Mit object o = Activator.CreateInstance(t, true); kann nun in obigem Beispiel eine Instanz des Objektes durch Aufruf des privaten parameterlosen Konstruktors erzeugt werden. Hier muss man natürlich jetzt sicherstellen, dass die Pflichtobjekte entsprechend befüllt werden.
 Am Dienstag werde ich auf der VSOne zwei Vorträge halten 13:45 - 14:45 Databinding in WinForms für Fortgeschrittene Databinding ist mehr als die oft gezeigten Drag&Drop-Beispiele. Vor allem mit Objekten, typisierten DataSets und User Controls eröffnen sich enorme Möglichkeiten. Diese Session fasst die wichtigsten Infos aus jahrelanger Projekterfahrung zusammen.
15:15 - 16:15 Active Sync Wie bekomme ich Daten vom PC auf mein Mobile Device? Wie kann ich Daten auslesen? Diese Session zeigt, wie dieser Datenaustausch mit Hilfe von Active Sync bewerkstelligt werden kann und sie gibt wertvolle Hinweise, was in der Praxis zu beachten ist. Würde mich freuen, wenn der eine oder andere Leser meines Blogs auch auf der VSOne ist und wir uns mal persönlich kennenlernen.
Ich falle immer wieder darauf rein, deshalb jetzt mal zum merken! Das funktioniert nicht: foreach (DataRow dr in table1.Rows) table2.Rows.Add(dr); Das führt zu einer Fehlermeldung "This row already belongs to another table.". Statt dessen muss das lauten: foreach (DataRow dr in table1.Rows) table2.ImportRow(dr);
Wer Anwendungen für Pocket PCs oder andere mobile Geräte entwickelt oder präsentieren möchte, findet einige hilfreiche Tools im Windows Mobile Developer Power Toys Paket, das kostenlos heruntergeladen werden kann. Unter anderem findet man darin das ActiveSync Remote Display, mit dem man den Bildschirm des PDAs auf dem PC darstellen und den PDA sogar mit der Maus und der Tastatur des PCs steuern kann.  Link to Download details: Windows Mobile Developer Power Toys
Die Workitems von Team System lassen sich ja einfach in Excel abfragen und bearbeiten. Jedoch war ich mit den angeboteten Spalten nicht zufrieden. Man kann zwar über einen entsprechenden Button noch beliebige weitere Spalten abrufen, das aber jedesmal zu tun war dann doch ein wenig nervig. Nach einigem Suchen habe ich dann die Lösung gefunden. Man muss sich einfach eine eigene Query anlegen und dort die gewünschten Spalten definieren. Wenn man nun über diese Query die Workitems in Excel abfragt, kommen genau die Spalten, die in der Query definiert sind.
Mit OleDB lassen sich sehr einfach Excel-Dateien lesen. Man macht sich einen Connectionstring der ungefähr so aussieht:
Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & ExcelFileName & ";Extended Properties='Excel 8.0;HDR=No;"
Nun kann man eine ganz normale Connection öffnen und wie gewohnt z.B. über ein Select-Statement ein DataSet befüllen.
Dim conn As OleDbConnection = New OleDbConnection(connectionString) conn.Open() Dim dt As DataTable = New DataTable() Dim oleDbDataAdapter As OleDbDataAdapter = New OleDbDataAdapter("SELECT * FROM [Tabelle1]", conn) oleDbDataAdapter.Fill(dt) oleDbDataAdapter.Dispose() oleDbDataAdapter = Nothing conn.Close()
Das Problem ist dabei, wenn in Excel z.B. Integer und Textwerte in einer Spalte gemischt stehen und die Integerwerte dabei überwiegen, wird diese Spalte als Integer angelegt und die Textwerte stehen im Dataset dann als NULL. Das kann man umgehen, wenn man am Connectionstring den Parameter IMEX=1 anhängt. Damit wird ein "ImportMixedTypes"-Mode aktiviert, der gemischte Spalten immer als Text interpretiert.
Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Me.tbImportdatei.Text & ";Extended Properties='Excel 8.0;HDR=No;IMEX=1'"
Das Problem bei der ganzen Sache ist nur, dass nun standardmäßig die ersten 8 Zeilen geprüft werden. Sind diese alle Integers, wird die Saplte auch als Integer definiert, auch wenn weiter unten noch Textwerte kommen. Man findet hier an verschiedenen Stellen den Hinweis auf einen weiteren Parameter MaxScanRows. Dieser scheint aber nicht zu funktionieren, wie man auch aus diesem MSDN-Artikel ersehen kann. Statt dessen muss man die Einstellung in der Registry vornehmen, wenn man eine andere Anzahl prüfen möchte. Hierzu passt man im Zweig
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel
den Parameter TypeGuessRows an. Dieser Wert kann auf 1-16 Zeilen eingestellt werden. Ein Wert von 0 bedeutet dass die ersten 16384 Zeilen geprüft werden, um festzustellen, ob der mixed Mode verwendet werden muss oder ob der Datentyp eindeutig bestimmt werden kann. Dass das eigentlich keine saubere Lösung ist, ist klar. Wer will schon seinen Kunden zumuten, in der Registry rumzupfuschen? Aber es scheint im Moment keine bessere Lösung zu geben.
HDR=No bedeutet im obigen Fall übrigens, dass die Excel-Datei keine Header-Zeile hat.
Team Foundation Sidekicks ist eine Sammlung von Tools, die verschiedene Aufgaben bei Nutzung und Verwaltung von Team Foundation Server erleichtern. Unter anderem wird eine vereinfachte Verwaltung von Labels angeboten:

Link to Team Foundation Sidekicks
Lars Keller berichtet über das Tool IEeee, das es ermöglicht, direkt aus dem IE einen Fehlerbericht mit detailierten Informationen als WorkItem im Team System Server anzulegen. Das Tool dürfte vor allem für Tester sehr interesant sein. Link to IEeee: Home
Crum for Team System ist ein kostenloses add-in für Visual Studio Team System, das agile Entwicklungsmethoden nach Scrum unterstützt.
Link to Scrum for Team System
Um einen Label auf einer WinForm per Code einfach fett zu machen, funktioniert leider folgende Methode nicht:
TitleLbl.Font.Bold = true;
Statt dessen kann man aber folgenden Code verwenden:
TitleLbl.Font = new Font(TitleLbl.Font, FontStyle.Bold);
WorkItems für den Team Foundation Server lassen sich einfach per Code erstellen.
TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer("tfs-test");
WorkItemStore store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
WorkItemType wiType = store.Projects[0].WorkItemTypes[1];
WorkItem newWI = new WorkItem(wiType);
newWI.Title = "Title";
newWI.Save();
Für den Code müssen noch folgende Namespaces referenziert und eingebunden werden:
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
Dazu muss das Visual Studio SDK installiert sein.
Zu beachten ist, dass die Angaben für die Eigenschaften des WorkItems sprachspezifisch sind. Auf einem deutschen Server wird folgender Code nicht laufen:
newWI.State = "Active";
Auf dem deutschen Server muss das dann heissen:
newWI.State = "Aktiv";
Unschöner zu lesen, aber dafür sprachunabhängig ist die Verwendung von IDs.
Um übrigens ein Workitem zu lesen, kann folgender Code verwendet werden:
WorkItem newWI2 = store.GetWorkItem(92);
Möchte man einen enum-Wert an eine ComboBox binden, dann muss man hier einen kleinen Trick anwenden. Ich habe das mal am Beispiel mit dem UltraComboEditor aus der Infragistics-Bibliothek realisiert. Man braucht zunächst einen Parse_Event auf dem Binding:
this.ultraComboEditor1.DataBindings[0].Parse += new ConvertEventHandler(ValueInputEnum_Parse);
Dann kann man in dem Eventhandler den Wert in den Enum konvertieren:
void ValueInputEnum_Parse(object sender, ConvertEventArgs e) { e.Value = Enum.Parse(typeof(ePeriodInterval), e.Value.ToString()); }
Unter .net 1.1 hat man das Problem, dass Panels und andere scrollbaren Controls keinen Event liefern, wenn das Control gescrollt wird. Wie man das beheben kann, beschreibt Rick Brewster hier: http://blogs.msdn.com/rickbrew/archive/2004/06/24/165493.aspx
Bei .net 2.0 besteht das Problem übrigens nicht mehr, hier bringen die Controls den Event auch Eigenschaften über die horizontale und vertikale Bildlaufleiste mit.
In München findet am 13. und 14. Februar 2007 die Entwickler-Konferenz VSOne statt. In 8 Tracks werden sehr interessante Sessions rund um die Software-Entwicklung mit .net angeboten:
- Windows Forms - Windows Mobile - Web 2.0 - Advanced Development (ADC) - Visual Basic - SQL Server & BI - Business Fasttrack - Tools&Solutions
Ich werde dort zwei Vorträge halten, einen zum Thema Databinding in Winforms, einen zum Datenaustausch mit mobilen Devices über Active Sync.
Nähere Infos unter www.vsone.de

Will man in einem Web-Service Sessions nutzen, so muss der Client Cookies handeln können. Ist der Client eine Web-Applikation, so ist das kein Problem. Bei WinForms muss man da zu einem kleinen Kniff greifen.
Man muss für den Service einen CookieContainer erstellen. Dazu kann man im Client folgenden Code verwenden:
WebService.MyService ws = new WebService.MyService(); ws.CookieContainer = new CookieContainer();
Damit kann dann auch der Windows-Client Cookies handeln.
Mit Microsoft Sandcastle lassen sich die XML-Kommentare aus dem Sourcecode in eine Dokumentation konvertieren. Damit lassen sich ohne viel Aufwand Dokumentationen im Stile einer MSDN-Dokumentation erstellen, die sogar in die VS-Hilfe eingebunden werden können. Einen Einstieg bietet das folgende Tutorial von Jonas:
http://www.dotnet-ulm.de/Downloads/20061121/Sandcastle.zip
Es gibt ein Control mit dem Namen DSOFramer, das es erlaubt, Office-Anwendungen in eine eigene WinForms-Anwendung zu integrieren. Das Control hat allerdings einen Schönheitsfehler, es funktioniert nicht auf MDIChild-Forms. Versucht man innerhalb eines MDIChilds per Code eine Datei im DSOFramer zu laden, erhält man eine nichtssagende Fehlermeldung. Über einen kleinen Trick lässt sich das Problem allerdings beseitigen. Man baut sich einfach ein Usercontrol, in das man den DSOFramer steckt. danach funktioniert das Control auch in MDIChilds.
Infos und Download des DSOFramer_Controls unter http://support.microsoft.com/kb/311765
Dank an Christopher für den Tipp.
artiso, mein Arbeitgeber, sucht momentan einen .net-Entwickler zur Festanstellung. Falls jemand Interesse hat oder jemanden kennt, der im Moment einen Job sucht, der kann gerne mit mir Kontakt aufnehmen.
Hier die Stellenanzeige:
Die artiso solutions GmbH, ein ein visionäres .net Entwicklungsunternehmen in der Nähe von Ulm sucht zum nächstmöglichen Zeitpunkt einen/eine
.net Entwickler/-in
Die artiso entwickelt individuelle Softwarelösungen für groß- und mittelständische Unternehmen in Süddeutschland. Hierbei kommen sowohl Web- als auch Windows-Technologien und Smart Devices zum Einsatz. Es werden modernste Entwicklungstechnologien, zum Beispiel .net 3.0 ebenso wie innovative Architekturansätze und moderne Entwicklungstools eingesetzt.
Wir bieten unseren Entwicklern-/innen die Möglichkeit, sich mit innovativen Technologien zu beschäftigen. In unserem Team kann sich jeder seinen individuellen Neigungen entsprechend einbringen und Verantwortung übernehmen.
Nähere Informationen erhalten Sie unter http://www.artiso.com/ oder via e-Mail unter tschissler@artiso.com.
Um den aktuell angemeldeten Windows-User zu ermitteln gibt es zwei Möglichkeiten:
1.) string userName = Environment.UserName Diese Variante liest aus der Systemumgebung die entsprechende Einstellung aus. Nachteil: Diese Einstellung kann leicht manipuliert werden, z.B. in der Eingabeaufforderung mit Set USERNAME = Administrator
2.) string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name; Diese Variante fragt den User direkt im Windows Sicherheitsystem ab und kann deshalb nicht manipuliert werden.
Hat man eine umfangreiche Form mit vielen Controls, ist es oft nicht einfach, den Überblick über die Tab-Reihenfolge der Form zu behalten. Und für den Anwender ist es ärgerlich, wenn er bei Tastaturbedienung wild auf der Eingabemaske herum geführt wird. IN VS 2005 gibt es im Menü Ansicht hier einen Eintrag, der hier eine Lösung bietet . Ruft man den Menüpunkt Aktivierreihenfolge (Taborder) auf (ist nur verfügbar wenn das aktive Fenster eine Winform enthält), wird die Form in einem speziellen Modus dargestellt und auch der Cursor ändert sein Aussehen.
Die Zahlen, die nun bei jedem Control angegeben werden, geben die Tabreihenfolge an. Hat man Gruppierungselemente wie z.B. Panels, so werden durch Komma getrennt erst die Reihenfolge der Gruppen und dann die des Controls angezeigt.
Um die Tabreihenfolge zu ändern beginnt man nun einfach die Controls in genau der Reihenfolge anzuklicken, wie man sie haben möchte. Die Zahlen werden sofort angepasst.
Um den Modus wieder zu verlassn, muss man den Menüpunkt im Menü Ansicht einfach wieder deaktivieren. So einfach erhält man saubere Tabreihenfolgen.
Oft hat man das Problem, dass man eindeutige, fortlaufende Nummern erzeugen möchte. In einer MultiUser-Umgebung braucht man dazu eine zentrale Instanz, die gleichzeitige Zugriffe mehrere User korrekt verwaltet, typischerweise eine Datenbank. Mit Oracle z.B. kann man diese Nummern mit Hilfe einer Sequenz erzeugen.
CREATE SEQUENCE SOPTOOLS.SEQSOPNUMMER START WITH 1 INCREMENT BY 1 MINVALUE 0 NOCACHE NOCYCLE NOORDER
Die Parameter sind eigentlich weitgehend selbsterklärend. Die Meisten Beispiele findet man, wenn man nun mit Hilfe des INSERT-Befehls einen neuen Eintrag erzeugen möchte. Das sieht dann ungefähr so aus:
INSERT INTO SOPS (SOPNUMMER, SOPNAME) VALUES (SEQSOPNUMMER.NEXTVAL,'NeueSOP')
Damit wird ein neuer Datensatz angelegt. Dabei wird die Sequenz automatisch um eins erhöht und der neue Wert als SOPNUMMER eingetragen. D.h. wenn der Befehl mehrfach hintereinander ausgeführt wird, hat jeder Eintrag eine eindeutige SOPNUMMER. Mit .CURRVAL kann man übrigens auf die Sequenz zugreifen, ohne dass der Wert erhöht wird.
Bei mir war's aber so, dass ich einfach nur den nächsten Wert der Sequenz wollte ohne einen INSERT. Da muss man zu einem kleinen Trick greifen. Man kann die Sequenz nicht direkt abfragen, sondern immer nur in Verbindung mit einer Tabelle. Hier bietet Oracle die Pseudo-Tabelle DUAL, die für diesen Zweck super geeignet ist. Sie enthält genau eine Zeile mit einer Spalte. Damit liefert folgende Abfrage den nächsten Wert der Sequenz und erhöht die Sequenz automatisch:
SELECT SEQSOPNUMMER.NEXTVAL FROM DUAL
Ich bin jetzt auch auf der Blog-Liste der DtoNetGerman Bloggers gelistet. Einfach mal vorbeischauen, dort sind sehr interessante deutschsprachige Blog versammelt. Link to DotNetGerman Bloggers
Mit dem patterns & practices Guidance Explorer wird dem Entwickler ein Tool an die Hand gegeben, mit dem er entsprechende Entwicklungs-Patterns und Best Practices zu verschiedenen Themen gefunden werden können. Darüber hinaus kann man eigene Checklisten und eigene Guidance-Sets erstellen. Link to patterns & practices Guidance Explorer
Diese Community-Seite beschäftigt sich hauptsächlich mit der Entwicklung von Software für die Windows Media Center Edition. Link to Code-Green.de
Will man eine Liste mit allen Werten eines enums befüllen, z.B. zur Ausgabe in einer DropDown-List, kann man folgenden Code verwenden:
foreach (int Entry in Enum.GetValues(typeof(DataLayer.LogDataLayer.LogDataLayer.LogEntryTypes))) { vl.ValueListItems.Add(Entry, ((DataLayer.LogDataLayer.LogDataLayer.LogEntryTypes)Entry).ToString()); }
Ich erstelle gerade eine Anwendung, die verschiedene Berechnungen durchführt. Um möglichst flexibel zu sein, habe ich jede Berechnungsmethode in eine eigene DLL gepackt. Diese DLLs sollten nun nicht zur Compile-Zeit eingebunden werden sondern erst zu Laufzeit. Dadurch kann man jederzeit zusätzliche Berechnungsmethoden erstellen und diese dann einfach in das Anwendungsverzeichnis kopieren ohne die gesamte Anwendung neu compilieren zu müssen. Das Ganze funktioniert sogar zur Laufzeit, d.h. die Anwendung muss nicht neu gestartet werden, wenn eine neue DLL hinzukommt.
Das Ganze funktioniert so:
- Ich habe ein Interface erstellt, das als Schnittstelle für alle Berechnungsmethoden dient.
public interface IBaseEngine { void StartCalculation(); }
- Dann habe ich ein Berechnungsmodul erstellt, das die Schnittstelle implementiert. Berechnungsmodul und Interface sind im gleichen Namespace:
public class cCapaPlanerEngine : IBaseEngine { public cCapaPlanerEngine() { }
public void StartCalculation() { // Hier kommt die Berechnung } }
- Nach dem Compilieren wird die DLL des Berechnungsmoduls in das Anwendungsverzeichnis kopiert.
- Nun kann das Berechnungsmodul instanziiert werden:
IBaseEngine calculationEngine = (IBaseEngine)Activator.CreateInstanceFrom("CalculationEngines\\" + _CalculationEngineName + ".dll", "ScenarioGenerator.CalculationEngines.c" + _CalculationEngineName).Unwrap();
Da sind noch ein paar statische Sachen drin, die besser in die config ausgelagert bzw. automatisch ermittelt werden, aber so ist es momentan etwas verständlicher. Wichtig ist das Unwrap() am Ende, da sonst der Typecast nicht funktioniert. Eine optimierte Version könnte etwa so aussehen, wobei hier in derm Berechnungsmodul nur eine Klasse stehen sollte:
Assembly calculationEngineAssembly = Assembly.LoadFrom(Properties.Settings.Default.CalculationEnginesPath + "\\" + _CalculationEngineName + ".dll"); calculationEngine = (IBaseEngine)Activator.CreateInstance(calculationEngineAssembly.GetTypes()[0]);
- Nun kann die Berechnungsmethode einfach aufgerufen werden:
calculationEngine.StartCalculation();
Weitere Berechnungsmodule lassen sich nun einfach erstellen indem sie die selbe Schnittstelle implementieren und dann einfach in das Anwendungsverzeichnis kopiert werden.
Man kann eigene enums in den Settings einer Anwendung avblegen. Dazu muss zunächst der enum definiert werden. Anschließend öffnet man die Settings-Datei des Projektes (liegt unter Properties). Im Feld Type kann man hier nun Browse... auswählen. Dann gibt man bei SelectedType den vollqualifizierten Namen inkl. Namespace ein. Nun kann man in der Spalte Value über eine DropDownList den gewünschten Wert für die Konfiguration auswählen. In der app.config sieht das dann so aus: < CalculationUnitApplication.Properties.Settings> <setting name="Setting" serializeAs="String"> <value>CapaPlaner</value> </setting> </CalculationUnitApplication.Properties.Settings> Auf den Eintrag kann man dann aus dem Code so zugreifen: Properties. Settings.Default.mySetting wobei mySetting der Name ist, der dem Eintrag in der Settings-Einstellung im Feld Name vergeben wurde. Das Ganze ist jetzt typsicher, d.h. wenn jemand die Config-Datei bearbeitet und gibt einen Wert ein, der nicht im enum vorkommt, wird eine Exception geworfen.
Weder was zum Essen noch glänzt es, aber man wird reicher damit, zumindest an Wissen. Die MSDN-Nuggets sind Kurzfilme, die in 10-15 Min. Schritt für Schritt in ein Thema einführen. Gut davbei ist, dass man nach Thema und nach dem Niveau (Einsteiger - Experte) suchen kann.
Link to MSDN Nuggets
Wenn auf einer DataTable ein ColumnChanged-Event eingesetzt wird um bei Änderungen eines Wertes in der DataTable andere Werte in der selben table neu zu berechnen, ergibt sich das Problem, dass das zurückschreiben der neuberechneten Werte wieder zu einem ColumnChanged führt, was den Evbenthandler erneut aufruft und so in einer Endlosschleife endet, die mit einem StackOverflow endet.
Hier gibt es eine recht simple Abhilfe. Man deregistriert den EventHandler bevor die geänderten Werte geschrieben werden und registriert ihn danach einfach wieder. Das kann dann z.B. so aussehen:
void myTable_ColumnChanged(object sender, DataColumnChangeEventArgs e) { myDataSet.myTable.ColumnChanged -= new DataColumnChangeEventHandler(myTable_ColumnChanged); RecalculateValues(); myDataSet.myTable.ColumnChanged += new DataColumnChangeEventHandler(myTable_ColumnChanged); }
Folgender Code zeigt, wie man in eine Zelle im Infragistics-Grid Prozentwerte aus- und eingeben kann. Zu beachten ist hierbei, dass beim BeforeExitEditMode auf die Text-Eigenschaft zugegriffen werden muss, da der Value zu diesem Zeitpunkt noch nicht gesetzt ist.
private void ugShiftDetails_BeforeEnterEditMode(object sender, CancelEventArgs e) { if (this.ugShiftDetails.ActiveCell.Column.Key == "PercentColumn") { UltraGridCell c = this.ugShiftDetails.ActiveCell; c.Value = ((double)c.Value) * 100; } }
private void ugShiftDetails_BeforeExitEditMode(object sender, Infragistics.Win.UltraWinGrid.BeforeExitEditModeEventArgs e) { if (this.ugShiftDetails.ActiveCell.Column.Key == "PercentColumn") { UltraGridCell c = this.ugShiftDetails.ActiveCell; try { c.Value = Double.Parse(c.Text) / 100; } catch { MessageBox.Show("Invalid Input"); } } }
Die Lebensdauer eines Hosts und damit auch der Instanzen der darin enthaltenen Member kann über ein Attribut gesteuert werden. Mein konkreter Anwendungsfall war, dass ich einen Status speichern wollte, der von allen Clients über die gesamte Laufzweit meines Servers abgefragt werden kann. Der Host sollte dazu am einfachsten während der gesamten Laufzeit des Servers als einzige Instanz zur Verfügung stehen. Dazu einfach folgendes Attribut zur Host-Definition hinzufügen: [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class cClientHost : IClientInterface Über dieses Attribut lässt sich z.B. die Lebensdauer auch für die auer einer Session einrichten.
Die Fa. artiso (www.artiso.com) für die ich arbeite, sucht momentan einen .net Entwickler. Der Entwickler sollte über folgende Kenntnisse bzw. Eigenschaften verfügen:
- C#, SQL, Winforms, ASP.Net
- Projekterfahrung
-
Selbständiges Arbeiten
-
Qualitätsbewußtsein
Wenn jemand Inteeresse hat bzw. jemand kennt, der Interesse hat, können nähere Informationen unter tschissler@artiso.com erfragt werden.
Paint.Net ist ein kostenloses Grafik-Tool, das umfangreiche Funktionen zur Bearbeitung von Grafiken bietet. Gerade für Entwickler düfte das Tool vollkommen ausreichen und auch eine echte Alternative zu Photshop & Co sein.
http://www.getpaint.net/
Danke an Jonas für den Link
Um in Excel Zellen bis ans Ende einer datenreihe aufzufüllen (z.B. eine Summenformel etc.), kann man einfach den zu übernehmenden Bereich markieren und dann auf das kleine Kästchen rechts unten im selektierten Bereich doppelklicken.
Ich wollte nun das gleiche Ergebnis per VBA erreichen. Dazu habe ich die zu kopierende Zelle erst mal mit dem Namen "Copy" versehen. Dann kann man mit dem folgenden Befehl das AutoFill ausführen:
Range("Copy").AutoFill Destination:=Range("H3:H" & Range("G65535").End(xlUp).Row), Type:=xlFillDefault
Damit wird der Bereich "Copy" von der Zelle H3 bis Hx kopiert, wobei x die letzte Zeile der Spalte G ist, die einen Wert enthält.
In seinem Blog beschreibt bharry einige Fixes und neue Features des SP1 Beta für Team Foundation Server. Scheint wohl jetzt neu zu sein, auch für Service-Packs Betas anzubieten. Na ja so kommt man früher dran und es sind hinterher hoffentlich weniger Fehler drin - mal abwarten. http://blogs.msdn.com/bharry/archive/2006/09/26/772371.aspx
Das Tool selber hat zwar mit .net nix zu tun, ist aber für den Entwickler trotzdem interessant. Es gibt die System-Infos auf dem Desktop aus. Funktioniert auch, wenn man eine Hintergrundgrafik eingestellt hat. http://www.sysinternals.com/Utilities/BgInfo.html 
Beim Databinding möchte man oft Einfluss auf die Darstellung der Werte auf der Oberfläche nehmen. Ein typischer Fall hierzu ist z.B. das Databinding mit Prozentwerten. Hier hat man z.B. einen Wert 0,5 der als 50% angezeigt werden soll. Wenn der Benutzer dann 40% eingibt, soll dieser Wert in 0,4 konvertiert werden. Hierzu kann man die Format- und Parse-Events des Databindings verwenden.
Zuerst müssen die Events definiert werden. Dabei gehen wir in dem Fall davon aus, dass es sich um das erste Databinding auf dem Control handelt.
this.txtValue.DataBindings[0].Format += new ConvertEventHandler(ValueInputPercent_Format); this.txtValue.DataBindings[0].Parse += new ConvertEventHandler(ValueInputPercent_Parse);
Dann können in den Eventhandlern die entsprechenden Formatierungen vorgenommen werden. Dies können natürlich auch noch mit entsprechenden Fehlerprüfungen versehen werden.
void ValueInputPercent_Parse(object sender, ConvertEventArgs e) { e.Value = Double.Parse(e.Value.ToString().TrimEnd('%')) / 100; }
void ValueInputPercent_Format(object sender, ConvertEventArgs e) { e.Value = ((double)e.Value) * 100 + "%"; }
User-Controls werden im Designer von Visual Studio genauso instanziert wie zur Laufzeit. Um hier unterscheiden zu können, kann man mit der Variable DesignMode abfragen, in welchem Modus die Komponente momentan initialisiert wird. Die ist z.B. sinnvoll, wenn man beim instanzieren auf Objekte zugreift, die im DesignMode gar nicht zur Verfügung stehen. Hier ein kleines Beispiel:
public MyControl() { InitializeComponent(); if (!DesignMode) { try { shiftConfiguration.ReadXml(ConfigurationManager.AppSettings["ShiftConfigFile"]); } catch (Exception ex) { MessageBox.Show("Error reading Shift Configuration File\n\nError : " + ex.Message); } } }
Ich habe heute ein Update meiner Blog-Software eingespielt. Es gibt da im Moment noch ein paar kleinere Probleme z.B. mit den Kommentaren. Ich bin dabei das zu beheben. Wenn jemand sonst noch Fehler auffallen, bitte mir kurz melden.
Als Erweiterung zu meinem Beitrag zum Übernehmen von Excel-Daten über die Zwischenablage (http://www.artiso.com/ProBlog/PermaLink,guid,2017b61d-19f4-4e4a-a033-cbf820d2b18e.aspx) hier nun das Gegenstück, Daten über die Zwischenablage an Excel übergeben:
string Data = "1,1;2,7;3,1;4,8;5,9"; Byte[] ClipboardData = Encoding.UTF8.GetBytes(Data); MemoryStream ClipboardStream = new MemoryStream(ClipboardData); DataObject DataObj = new DataObject(DataFormats.CommaSeparatedValue, ClipboardStream); Clipboard.SetDataObject(DataObj, true);
Daten über mehrere Zeilen werden übrigens mit Environment.NewLine getrennt.
Der nachfolgende Code zeigt, wie JPEG Grafiken (und ebenso auch andere Formate) verlustlos rotiert werden können:
Image i = Image.FromFile(this.imageFilename); ImageCodecInfo usedIC = this.GetEncoderInfo("image/jpeg");
System.Drawing.Imaging.Encoder encoder = System.Drawing.Imaging.Encoder.Transformation;
EncoderParameters encparams = new EncoderParameters(1); EncoderParameter encparam = new EncoderParameter(encoder, (long)EncoderValue.TransformRotate270); encparams.Param[0] = encparam;
i.Save("filename.jpg", usedIC, encparams );
i.Dispose(); i = null; GC.Collect();
Quelle: http://blog.norberteder.com/index.php?entry=entry060920-223506
.net bietet keine Funktion, um eine Form einfach auszudrucken. Diese Lücke schließt nun Microsofts PrintForm Component 1.0.
http://www.microsoft.com/downloads/details.aspx?familyid=286111b0-6965-46cc-bf6f-c5ee63b1f98c&displaylang=en#filelist
Damit läßt sich bereits mit 2 Zeilen Code eine Form ausdrucken.
this.printForm1.Form = this; this.printForm1.Print();
Die Komponentebietet darüber hinaus noch eine Vielzahl von Einstellmöglichkeiten, z.B. zur Anzeige einer Druckvorschau etc.
Übrigens nicht durch den Namespace (Microsoft.VisualBasic.Powerpacks) irritieren lassen, die Compunente funktioniert auch unter C# 
User-Controls können auch mit eigenen Events erweitert werden. Das ist eigenlich recht simpel. Man definiert einfach einen Event, z.B.
public event EventHandler LinesChanged;
Dann ruft man an der Stelle, an der der Event ausgelöst werden soll einfach den Event auf. Das geht am einfachsten über:
LinesChanged(this, EventArgs.Empty);
Der Event kann dann außerhalb des User-Controls wie gewohnt mit einem Eventhandler ausgewertet werden. Möchte man mehr Informationen als den Sender übergeben, erstellt man sich einfach eine Klasse, die man von EventArgs ableitet und übergibt dann eine Instanz dieser Klasse beim Aufruf des Events, z.B.
public class MyEventArgs : EventArgs { private string msg;
public MyEventArgs( string messageData ) { msg = messageData; } public string Message { get { return msg; } set { msg = value; } } }
Damit der Eventhandler nun auch noch den richtigen Datentyp für die EventArgs übergeben bekommt braucht mann noch ein Delegate, z.B.
public delegate void MyEventHandler(object sender, MyEventArgs e);
Der Event muss nun entsprechend deklariert werden:
public event MyEventHandler LinesChanged;
Um den Eventhandler nun zu erzeugen, legt man in der umgebenden Klasse eine Instanz des Objektes an, das den Event wirft. Auf dieser Instanz kann man nun den Event mit dem Handler verbinden. Das geht in VS ganz einfach. Man gibt z.B. ein:
MyControl.LinesChanged +=
Dann drückt man zweimal Tab und schon hat man den Eventhandler angelegt. Fertig sieht das dann ungefähr so aus:
MyControl.LinesChanged += new UControl.MyEventHandler(MyControl_LinesChanged)
void MyControl_LinesChanged(object sender, MyEventArgs e) { throw new Exception("The method or operation is not implemented."); }
Mit WCF (Windows Communication Foundation) lassen sich Service orientierte Architekturen (SOA) implementieren. Der Vorteil gegenüber bestehenden technologien besteht darin, dass die eigentliche Schnittstelle von dem Nachrichtenformat und dem Transportweg unabhängig ist, d.h. mann kann einfach durch Konfiguration bestimmen, ob die Kommunikation über HTTP, TCP, MSMQ, Named Pipes etc. stattfinden soll und ob der Nachrichtenaustausch über SOAP/XML, Binärserialisierung etc. erfolgen soll. WCF ist bestandteil von .net 3.0
Im Rahmen eines Projektes habe ich begonnen, mich mit der WCF zu befassen. Die ersten Ergebnisse sind in dem folgenden Tutorial beschrieben. Das Dokument soll einen einfachen Einstieg in WCF bieten. Windows Communication Foundation Tutorial.pdf (847,8 KB)
Vor kurzem habe ich hier gepostet, wie man Debug-Informationen ausgeben kann. Hier noch eine kleine Ergänzung. Man kann den Debug-Informationen auch noch Informationen über die Quelldatei, das Modul und die Zeile ausgeben. Dazu dient der folgende Code:
Debug.WriteLine("Quelledatei = " + new StackFrame(0, true).GetFileName() + "\nMethode = " + new StackFrame(0, true).GetMethod() + "\nZeile = " + new StackFrame(0, true).GetFileLineNumber() + "\n");
Gefunden bei Dani.Net
Unter http://www.netfxguide.com/ finden sich jede Menge Links zu Webkasts, Tutorials, Artikel etc. zum Thema .Net 3.0. Die Inhalte sind in die Rubrichen WCF, WPF, WF und sonstiges gegliedert.
Auf Dani.NET habe ich folgenden interessanten Beitrag gefunden:
In wohl praktisch jeder Applikation müssen Settings für den Mail-Versand gespeichert werden - SMTP-Hoster, statische Sender-Adresse etc. Wer das wie ich bis jetzt immer mit eigenen Konfigurations-Abschnitten gelöst hat, der soll hier belehrt werden src="http://blogs.dotnetgerman.com/dani.net/smilies/happy.gif"> : <configuration> (...) <system.net> <mailSettings> <smtp from="info@mydomain.com"> <network host="my.smtp.host"/> </smtp> </mailSettings> </system.net> (...) </configuration>
So sieht ein entsprechender built-in Dokumentations-Abschnitt aus. Natürlich wäre es zB. auch möglich, entsprechende Credentials für den SMTP-Server zu definieren.
Wenn nun ein Mail-Objekt erstellt wird und über die Klasse SmtpClient versendet wird, werden automatisch die entsprechenden Daten aus dem Config-File genommen.
Heute habe ich mir mal Outlook 2007 näher angeschaut und dabei bin ich über die Funktion gestolpert, mit der Outlook RSS Feeds lesen kann. Eigentlich bin ich mit dem SharpReader, den ich bisher einsetze, ganz zufrieden. Einzig sört mich, dass ich auf verschiedenen Rechnern nicht sauber synchronisieren kann, welche Einträge ich schon gelesen habe.
In Outlook werden die Einträge der Feeds werden in Outlook als Nachrichten auf dem Exchange-Server abgelegt. Daraus ergeben sich zwei Vorteile:
1.) Die Einträge stehen auf allen Rechnern zur Verfügung. Auch der Status (gelesen / ungelesen) wird für alle Outlook-Clients zur Verfügung gestellt.
2.) Ich kann die Einträge auch offline lesen. Dazu bietet Outlook auch die Möglichkeit, den kompletten Eintrag als HTML-File lokal zu speichern.
Total begeistert war ich dann, als ich feststellte, dass ich sogar mit meinem Outlook 2003 auf die heruntergeladenen Einträge Zugriff habe. OPML-Files können übrigens über die Import / Export-Funktion von Outlook importiert und auch wieder exportiert werden.
Nachträgliche Einstellungen können über einen etwas versteckten Dialog vorgenommen werden: Tools / Options / Mail Setup / E-mail Accounts / RSS-Feeds
Seit ca. 2 Monaten blogge ich nun und dies ist der 100ste Eintraig in meinem Blog. Mir macht es Spass und für mich ist der Blog auch ein gutes Nachschlagewerk. Die Statistik zeigt mir, dass es wohl den einen oder anderen gibt, der auch liest, was ich hier so von mir gebe.
Für mich wäre es klasse, hier ein wenig Feedback zu erhalten. Ich bin dankbar für Anregungen aller Art. Sind die Beiträge zu knapp oder zu ausführlich? Sind die Themen interessant? Hat es dem einen oder anderen evtl. schon bei einem konkreten Problem geholfen. Lesen Sie den Blog regelmäßig oder sind Sie über eine Suchmaschine nur zufällig darauf gestossen? Wie sind Sie auf den Blog gekommen etc. etc.
Ich würde mich freuen, wenn ich ein wenig Feedback bekommen könnte. Entweder über den Contact-Link auf der linken Seite oder einfach als Kommentar zu diesem oder Beitrag.
In manchen Situationen hilft ein Breakpoint beim Debugen einfach nicht weiter. Haben Sie schon mal versucht, einen Eventhandler für ein Mouse-Move-Ereignis mit einem Breakpoint zu debuggen? Das ist schlicht unmöglich.
Abhilfe schafft hier das Debug-Objekt. Sie können damit z.B. Informationen im Ausgabefenster von VS ausgeben. In oben beschriebenen Fall würden Sie also z.B. folgendes verwenden:
private void Form2_MouseMove(object sender, MouseEventArgs e) { System.Diagnostics.Debug.WriteLine(e.X + " - " + e.Y); }
Das Ergebnis sieht man wie gesagt im Ausgabefenster von Visual Studio (Einblenden über Strg + Alt + O).
Welche Entwickler hat denn schon die Namespaces aller Objekte des Frameworks im Kopf? Da hilft oft nur in der Hilfe nachschauen - oder man kennt eine kleine aber sehr nette Funktion im Visual Studio 2005!
Man gibt einfach den Namen des Objektes ein. Ist das Objekt im .net Framework enthalten, erkennt VS das automatisch und zeigt dies durch einen kleinen roten Strich am Ende des Objektnamens ein. Klickt man darauf, kann man auswählen, ob der Namespace vor dem Objekt eingefügt l oder ob automatisch ein Using für den Namespace eingefügt werden soll. Unten sieht man ein Beispiel mit dem Objekt MailMessage.
Eigentlich dachte ich, das sei eine ganz simple Aufgabe, aber dann hat mich das Ganze doch 2 Stunden Zeit gekostet. Das Ziel war, zwei Panels über einen separaten Scrollbar zu scrollen. Alse Panels in der Form platziert, AutoScroll auf false gesetzt, damit nicht jedes Panel mit einem Scrollbar versehen wird und den Scrollbar hinzugefügt. Der Event für das Scrollen war auch schenll gefunden, aber dann gab es Probleme.
Deshalb hier die Vorgehensweise, die nach meinen Versuchen am besten funktioniert hat.
private void Form2_Load(object sender, EventArgs e) { this.panel1.AutoScroll = true; this.panel2.AutoScroll = true; this.ultraScrollBar1.Minimum = this.panel1.HorizontalScroll.Minimum; this.ultraScrollBar1.Maximum = this.panel1.HorizontalScroll.Maximum; this.ultraScrollBar1.Value = this.panel1.HorizontalScroll.Value; this.ultraScrollBar1.SmallChange = this.panel1.HorizontalScroll.SmallChange; this.ultraScrollBar1.LargeChange = this.panel1.HorizontalScroll.LargeChange; this.panel1.AutoScroll = false; this.panel2.AutoScroll = false; }
private void ultraScrollBar1_Scroll(object sender, ScrollEventArgs e) { this.panel1.AutoScrollPosition = new Point(e.NewValue, 0); this.panel2.AutoScrollPosition = new Point(e.NewValue, 0); }
Hierzu ein paar Anmerkungen: 1.) Die Werte für Minimum, Maximum, SmalChange und LargeChange können vom Panel nur dann sauber abgefragt werden, wenn AutoScroll = true gesetzt ist. 2.) Wird die Scrollposition über this.panel1.HorizontalScroll.Value gesetzt, was naheliegend wäre, kommt es bei abgeschaltetem AutoScroll zu einem seltsamen Flimmer-Effekt. Statt dessen muss die AutoScrollPosition gesetzt werden. 3.) Auch für das zweite Panel muss das AutoScroll einmal aktiviert und dann wieder deaktiviert werden, sonst scrollt das nicht mit.
Also diese Lösung funktioniert mal.
Diese Vorgehensweise scheint mir jedoch recht unlogisch und sehr umständlich. Ob das Framework da nichts besseres bietet oder ob ich da einfach noch nicht den richtigen Dreh gefunden hab, weiss ich im Moment noch nicht. Ich werde bei Gelegenheit das mal vertiefen und an dieser Stelle wieder posten.
Zur Erstellung von Reports sind die Reporting Services des SQL-Servers recht bekannt. Dass aber auch Reports direkt in VS 2005 ohne SQL-Server erstellt werden können, ist weniger bekannt. Die Berichte können zur Laufzeit angepasst werden. Diese Reporting-Funktionalität kann einfach in eigene Anwendungen integriert werden. Durch ein offenes XML-Format können die Berichtsvorlagen auch aus eigenen Anwendungen heraus erzeugt werden.
In einem Web-Cast stellt Sebastian Weber die Funktionen aber auch die Unterschiede zu den SQL-Server Reporting-Services dar.
https://www.microsoft.com/germany/MSDN/webcasts/library.aspx?id=118771506
Auf dieser Seite wird der Einstieg in die .Net Programmierung an ein paar Beispielen Schritt für Schritt aufgezeigt. Damit kann wirklich jeder in die Programmierung mit .Net einsteigen und Interesse daran finden.
Vor allem bei der Aufmachung hat sich Microsoft echt was einfallen lassen.
http://www.microsoft.com/germany/msdn/aktionen/wirbauenwas/default.mspx
Wenn man seine Klassen sauber mit XML-Kommentaren versieht, ist es ein leichtes, daraus auch eine schöne Dokumentation zu erstellen. Nur beim eingeben der XML-Kommentare taucht oft die Frage aus, wie sieht das Ergebnis aus? Dazu jedesmal die Dokumentation zu erstellen ist recht mühsam. Abhilfe schafft hier dieses kleine Tool, das in der IDE eine HTML-Vorschau ermöglicht.
http://www.kyrsoft.com/opentools/qdocviewer.html

Bei Galileo-Computing kann man sich kostenlos das Openbook "Praxisbuch Objektorientierung" herunterladen. Ich habe es leider noch nicht gelesen, deshalb hier die Kurzbeschreibung des Verlages:
Kaum eine Software, die nicht mehr objektorientiert entworfen und entwickelt wird! Die beiden Autoren geben eine umfassende Einführung in die Prinzipien und die Anwendung der Objektorientierung. Das Buch ist aufgabenorientiert, bietet Beispiele in den Sprachen C++, Java, Ruby, und C# sowie ein Kapitel zur aspektorientierten Programmierung.
http://www.galileocomputing.de/openbook/oo/
Der Task-Manager liefert oftmals nur unzureichende Informationen über die einzelnen Prozesse etc. Mit dem Tool Process Explorer kann man zu jedem Prozess umfangreiche Informationen abfragen. Das Tool kann auch den Task-Manager ersetzen.
Sehr praktisch ist, dass man das Tool nicht installieren muss, sondern die Exe separat gestartet werden kann.
http://www.sysinternals.com/Utilities/ProcessExplorer.html
22:02 - Im Internet nach einem Tutorial gesucht. 22:10 - Genau das Passende gefunden. 22:11 - Ausdruck starten, um zu Hause zu lesen 22:12 - Geflucht, weil der rechte Rand mal wieder abgeschnitten ist
Für sole Probleme hat jeder so seinen eigenes Patentrezept, im Querformat drucken, nach Word kopieren und von da drucken oder - dieses kleine Tool installieren. Damit kann im IE die Seite so angepasst werden, dass Sie auf jeden Fall auf die Seite passt. Das Tool bietet auch eine Vorschau. Echt genial!
ACHTUNG - Bei der deutschen Version des IE muss das Icon manuell in die Symbolleiste eingefügt werden: Rechte Maustaste auf die Symbolleiste / Anpassen dann aus der linken Liste das Icon "Fit-width Print" in die rechte Liste übernehmen.
http://www.visiontech.ltd.uk/software/#IEPrint
Jeder Programmierer kennt das Problem. Am Entwicklungsrechner hat man einen schönen großen Monitor aber wie sieht die Anwendung bei einer anderen Auflösung, z.B. 1024 x 768 aus? Ein Fenster genau auf diese Größe zu bringen ist genau das, was Sizer tut. Man kann sich beliebige Größen defibnieren und dann einfach diese Größe für ein Fenster einstellen lassen.
http://www.brianapps.net/sizer.html
Mit diesem Tool lassen sich verschiedene Befehle auf Datenbanken ausführen. Damit lassen sich z.B. Daten einer Tabelle abfragen und nach CSV oder XML exportieren. Der besondere Charme des Tools ist, dass es nicht installiert werden muss, es kann einfach die EXE gestartet werden. Damit ist es gut geeignet als Datenbank-Viewer für unterwegs.
http://www.albahari.com/queryexpress.html
Ich habe im Speicher ein DataView mit ca. 22000 Datensätzen. Aus diesem DataView musste ich nun innerhalb einer Schleife 55 Abfragen machen. Dazu zwei Methoden:
dvINNs.RowFilter = "ProductDSID = " + drProducts["ProductDSID"];
foreach (DataRowView drINN in dvINNs) { ... }
oder
foreach (DataRow drINN in dvINNs.Table.Select("ProductDSID = " + drProducts["ProductDSID"])) { ... }
Ich habe eine Zeitmessung durchgeführt. Dies ergab für Methode I 1,5 Sek und für Methode II 0,03 Sek. D.h. der Select ist um Faktor 50 (in meinem Beispiel) schneller als der RowFilter.
Oft möchte man von einem DateTime-Wert die Kalenderwoche abfragen. Hierzu gibt es eine einfache Funktion:
Application .CurrentCulture.Calendar.GetWeekOfYear(CurrentDate, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
Dabei steht in CurrentDate das aktuelle Datum und die beiden anderen Parametern definieren Regeln, welche Woche als erste KW gilt. Standard in Deutschland ist dass der 1. Janur in KW 1 liegt, wenn dieser Tag ein Montag, ein Dienstag oder ein Mittwoch ist. Andernfalls zählt der 1. Januar noch zur letzten Woche des alten Jahrs und die KW1 beginnt am darauffolgenden Montag.
Um Einträge in die Toolbox von VS hinzuzufügen gibt es die Standard-Methode - rechte Maustaste, Elemente auswählen und sich dann die Elemente einzeln auswählen um sie hinzuzufügen. Weniger bekannt ist eine Methode, die gerade bei einer größeren Anzahl hinzuzufügender Controls schneller ist. Man kann die zugehörigen DLL-Dateien einfach per Drag & Drop aus dem Windows-Explorer auf die Toolbox ziehen.
Der kostenlose Internet Explorer Developer Toolbar von Microsoft bietet eine Fülle von sehr nützlichen Funktionen für Web-Entwickler. Der Toolbar integriert sich im Internet-Explorer. Man kann sich z.B. Objekte wie Tabellen, Bilder, DIVs etc. durch eine Umrandung hervorheben lassen oder man kann die komplette DOM-Struktur dursuchen und die Eigenschaften der Elemente abfragen und sogar verändern. Die Änderungen werden sofort sichtbar. Darüber hinaus werden noch eine vielzahl nützlicher Helfer angeboten, z.B. um Cookies anzuzeigen und zu löschen etc. Ein Tool, das bei keinem Web-Entwickler fehlen sollte!
http://www.microsoft.com/downloads/details.aspx?FamilyID=E59C3964-672D-4511-BB3E-2D5E1DB91038&displaylang=en
Oft möchte man den Monatsnamen eines Datums in der jeweiligen Landessprache des Anwenders ausgeben. Dies kann man einfach mit einer Zeile Code bewerkstelligen:
string MonthName = Application .CurrentCulture.DateTimeFormat.MonthNames[DateTimeValue.Month-1];
Alternativ kann man auch die Kurzform der Monate über die Eigenschaft AbbreviatedMonthNames abfragen.
Will man eine spezifische Sprache zur Ausgabe verwenden, kann man dies natürlich auch tun indem man einfach das entsprechende CultureInfo-Objekt verwendet:
CultureInfo ci = new CultureInfo("de-DE"); ci.DateTimeFormat.MonthNames[MonthID];
Unter http://www.galileocomputing.de/openbook/visual_csharp/index.htm kann man kostenlos den gesamten text des Buches "Visual C# 2005" lesen und auch herunterladen. Das Buch ist gut geschrieben und enthält umfangreiches Wissen zur Programmierung mit C#. Es sit auf dem aktuellsten Stand (C# 2.0) und geht auch auf alle wichtigen Neuerungen ein.
Mir hat das Buch so gut gefallen, dass ich mir gleich eine Print-Version gekauft habe. Aber es kann sich ja jeder kostenlos überzeugen 
Jedenfalls finde ich das Openbook-Konzept gut, da ich so die Katze nicht im Sack kaufen muss.
Im Infragistics-Grid lassen sich einfach dei Beschriftungen der einzelnen Gruppen der Outlook-Gruppierung einstellen. Hierzu muss lediglich der Event InitializeGroupByRow verwendet werden. Das folgende Beispiel ändert die Beschriftung so ab, dass nur die Bezeichnung der Gruppe ausgegeben wird.
private void ultraGrid1_InitializeGroupByRow(object sender, Infragistics.Win.UltraWinGrid.InitializeGroupByRowEventArgs e) { e.Row.Description = e.Row.Value.ToString(); }
In Ulm gibt es nun auch eine .net User-Group.
Die .net Developer-Group Ulm ist eine Organisation, die den Wissens- und Erfahrungsaustausch zwischen .net Entwicklern aus der Region Ulm und Oberschwaben fördern möchte. Jeder kann kostenlos und unverbindlich Mitglied werden.
In regelmäßigen Abständen werden Mitgliedertreffen abge-halten, bei denen Vorträge zu aktuellen Themen gehalten werden.
www.dotnet-ulm.de
Jede Menge Code-Snippets für alle Lebenslagen finden sich unter
http://dotnet-snippets.de/dns
Achtung Cookies müssen zugelassen werden, sonst funktioniert die Seite nicht korrekt.
Recht bekannt ist die Option im Infragistics Grid Datensätze durch einen Klick auf den Kopf einer Spalte zu filtern.

Es gibt aber auch die Möglichkeit, eine Zeile einzublenden, in der die Filterbedingung für jede Spalte eingegeben wird. Der Vorteil liegt dabei darin, dass auch nur Anfangsbuchstaben eingegeben werden können. Um dies zu erreichen, stellt man einfach im Designer Dialog unter Feature Picker die Option Filtering / Filter UI Type auf Filter Row. Das Ergebnis sieht dan so aus:
Wird eine Datei aus der TeamSystem SourceControl ausgecheckt, wird von dieser datei nicht automatisch die letzte Version gehohlt wie man das von VSS gewohnt ist. Der Grund dafür ist, dass dadurch evtl. ein inkonsistenter Zustand der Anwendung entstehen könnte, da die ausgecheckte Datei in einer neueren Version vorliegt, die nicht mit den restlichen dateien des Projekts kompatibel ist.
Weitere Ausführungen unter: http://blogs.vertigosoftware.com/teamsystem/archive/2006/05/15/2755.aspx
MSDN Solve ist die Lösung für alle Entwickler, die praxis-orientierte Hilfestellungen bei typischen Programmier-Herausforderungen suchen. MSDN Solve liefert verständliche Antworten auf immer wiederkehrende Fragen aus dem IT-Alltag und sorgt dafür, dass Sie Stolperfallen in Software-Projekten künftig leicht umschiffen.
http://www.microsoft.com/germany/msdn/solve/default.mspx
Die aktuelle Bildschirmauflösung abzufragen ist in .NET denkbar einfach, möchte man jedoch alle verfügbaren Auflösungen erfragen und eventuell sogar eine neue Auflösung setzen, muss man auf die Win32 API-Mittel zurückgreifen. Dieser Beitrag stellt eine Klasse zur Verfügung mit der mit jeweils einer Zeile Code über die verfügbaren Auflösungen iteriert werden bzw. eine neue Auflösung festgelegt werden kann
http://www.codegod.de/WebAppCodeGod/Main.aspx?pid=168
Ein wenig bekanntes Control ist das FlowLayoutPanel, das in VS 2005 standardmäßig enthalten ist. Mit diesem Control kann man Unterelemente in einer fließenden Ansicht darstellen wie das z.B. auch von Web-Seiten bekannt ist. Sie möchten eine Liste von Textboxen die untereinander stehen? Kein Problem mit dem FlowLayoutPanel. Sie können eine beliebige Richtung wählen (von rechts nach links, von oben nach unten etc.). Passen nicht alle Control in die Reihe, wird automatisch ein Umgruch eingefügt. Damit ist das FlowLayoutPanel wesentlich flexibler als man diese Funktion z.B. mit Docking erreichen könnte. Vor allem bei dynamisch generierten Control leistet das FlowLayoutPanel gute Dienste!
Oft möchte man Daten, die aus Excel in die Zwischenablage kopiert wurden, in der Anwendung verarbeiten. Dies geht recht einfach, da die Excel-Daten in der Zwischenablage einfach als CSV-Format vorliegen.
string ExcelValue = ""; IDataObject ClipboadData = Clipboard.GetDataObject(); if (ClipboadData.GetDataPresent(DataFormats.CommaSeparatedValue)) { StreamReader ExcelReader = new StreamReader((Stream)ClipboadData.GetData(DataFormats.CommaSeparatedValue)); while (!ExcelReader.EndOfStream) { ExcelValue = ExcelReader.ReadLine(); } }
Man holt sich die Daten aus der Zwischenablage und prüft diese, ob sie im CSV-Format vorliegen. Dann kann man mit Hilfe eines StreamReaders die Daten lesen. Die Daten kommen dann in einem Format wie z.B. 5,8;8,9;7,5. Das lässt sich nun problemlos in der eigenen Anwendung verarbeiten.
Um von generischen Objekten den Typ abzufragen kann man folgenden Code verwenden:
Dictionary<string, int> MyObject = new Dictionary<string, int>(); Type T = MyObject.GetType(); Type[] Ts = T.GetGenericArguments();
Dieser Code liefert ein Array zurück, das im ersten Element System.String und im zweiten System.Double enthält.
Weitere Infos unter http://msdn2.microsoft.com/en-us/library/b8ytshk6.aspx
Um die Work Items aller Team-Projekte eines Team-Servers anzeigen zu können, kann man einfach eine entsprechende Query anlegen. Hierzu einfach im Team-Explorer auf Work Items mit der rechten Maustaste klicken und dann "Add Query" auswählen. Die Query is dann schon mit einem Filter nach einem Projekt vorbelegt. Diesen einfach löschen, dann erscheinen alle Work Items.
Oft erhält mein eine Meldung in einer Message-Box und möchte den text kopieren. Mit Alt-Druck erhält man einen Screen-Shoot, aber das ist eine Grafik. Wie kommt man nun an den Text?
Mit Strg-C !
Oft müssem am Anfang und am Ende eines Strings überflüssige Zeichen gelöscht werden. Dazu kann in .Net der Befehl Trimm eingesetzt werden.
string t = " Test "; string Result = t.Trim(' ');
Mit Trim lassen sich aber auch mehrere Zeichen auf einmal löschen. Dabei ist die Reihenfolge der Zeichen egal!
string t = " \r\n Test \r \n "; string Result = t.Trim('\r', '\n', ' ');
In einer Anwendung aus der ich auf Access via COM zugreife, wollte ich das Access-Fenster ausblenden. Die "visible" Eigenschaft kann man auch setzten - es passiert nur nix, daher das ganze über DLLImport. Wichtig ist, dass man sich den/die "handle" auf das/die Fenster merkt - die findet man sonst nicht mehr und kann sie sonst auch nicht mehr sichbar schalten. Das Beispiel kann man natürlich auch auf jede andere Anwendung übertragen und das Process-Objekt hat ja auch noch paar andere Methoden, um ein bestimmtes Fenster zu finden, "GetProcessByID()" usw. sind auch vorhanden.
z.B. ausblenden von allen Access-Fenstern:
ArrayList processHandles = new ArrayList(); foreach (Process p in Process.GetProcessesByName("msaccess")) { ShowWindow((int)p.MainWindowHandle, 0); // 0 steht für unsichtbar processHandles.Add((int)p.MainWindowHandle); }
einblenden
foreach (int processHandle in processHandles) { ShowWindow(processHandle, 9); // 9 bedeutet restore - sprich so, wie das Fenster vor dem ausblenden aussah (Position, Größe) }
und der dllimport, damit die Funktion genutzet werden kann:
[DllImport("User32")]
private static extern int ShowWindow (int hwnd, int nCmdShow);
Mit MSBee kann MSBuild von VS2005 so konfiguriert werden, dass damit Anwendungen kompiliert werden können, die auf dem Framework 1.1 ablaufen. Dies kann vor allem zur Pflege von bestehenden Anwendungen sinnvoll sein. Neue Anwendungen zu erstellen ist jedoch recht mühsahm, weil VS 2005 automatisch partial Classes verwendet, die aber vom Framework SDK 1.1 nicht unterstützt werden.
http://www.codeplex.com/Wiki/View.aspx?ProjectName=MSBee
Unter IDesign gibt es einen Download, mit dem das My-Objekt von VB auch unter C# genutzt werden kann.
http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=-1&tabid=19&download=141
The My class in VB often simplifies and streamlines many operations, from Network programming to clipboard, to audio access, and so on. What takes sometimes a programming fit in C# can be done in one line using the My class in VB. If VB has Me and My, then C# should have this and That. The That class is the C# equivalent of the VB My class. It is a static class that uses the VB implementation as much as possible, and it requires adding a referencing to Microsoft.VisualBasic. The That class is instrumental when working in heterogeneous environments and when dealing with in porting of VB to C# or visa-versa.
Weitere interessante Downloads gibt's unter http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=5&tabid=11#ES
Unter http://www.red-gate.com/products/SQL_Prompt/index.htm kann man kostenlos ein kleines Tool herunterladen, das für alle SQL-Editoren wie z.B. den Query Analyzer, SQL Server 2005 Managementstudio etc. eine Intelli-Sense Unterstützung für Tabellen-, Aplaten und Funktionsnamen bietet.
Bisher war es recht mühsahm, Oberflächen für verschiedene Sprachen zu erstellen. Mit VS 2005 ist das jetzt ein Kinderspiel. Einfach auf der Form die Eigenschaft Localizable auf true setzen. Dann die Oberfläche für die Standard-Sprache aufbauen. Anschließend die Eigenschaft Language auf der Form auf eine explizite Sprache einstellen und Anpassungen vornehmen (Lables, Buttons etc. neu beschriften). VS legt für die Zweitsprache automatisch eine .resx-Datei an, in der diese sprachspezifischen Einstellungen gespeichert werden.
Während des editierens kann man beliebig zwischen den Sprachen umschalten und die Oberfläche für die jeweilige Einstellung editieren. Genial ist dabei, dass nicht nur Texte in den sprachspezifischen Ressource-Dateien gespeichert werden, sondern auch alle anderen Einstellungen. Wird ein Button z.B. in Englisch mit "Save" betittelt, kann es sein, dass die deutsche Bezeichnung "Speichern" zu lang ist und der Platz nicht ausreicht. Kein Problem. Den Button einfach in der deutschen Einstellung vergrößern und schon wird auch die Größe des Buttons in Abhängigkeit der Sprache gewählt.
Dass viele Operationen mit einem string recht langsam ist, ist ja weitgehend bekannt, auch dass man hier besser einen StringBuilder verwendet. Folgendes Beispiel ist unter Performance-Aspekten sehr ungünstig:
string Text = ""; for (int i=0; i<100000; i++) { Text += "x"; }
Was weniger bekant ist, die Erklärung dafür. Wird einem String ein neuer Wert zugeweisen, so wird das Objekt jedes mal neu angelegt. In dem obigen Beispiel wird also 100000 mal ein neues String-Objekt angelegt und das alte verworfen. Das kostet natürlich Zeit. Dahingegen ist der StringBuilder dynamisch erweiterbar. Nach der initialisierung wird er mit einer Kapazität von 16 Zeichen angelegt. Die Kapazität verdoppelt sich nun jedesmal, wenn die Kapazität überschritten wird. Mit dem einfügen des 17. Zeichens wird die Kapazität also auf 32 erhöht etc. Beim Stringbuilder kann man im Konstruktor auch schon eine größere Kapazität angeben.
In der AssemblyInfo.vb bzw. AssemblyInfo.cs gibt es zwei Einträge zur steuerung der Versionierung.
<Assembly: AssemblyVersion( "0.9.*")> <Assembly: AssemblyFileVersion("0.9.2.0")>
Das Problem dabei ist, dass die AssemblyVersion durch * automatisch nummeriert werden kann, dass das aber bei der AssemblyFileVersion nicht funktioniert. Möchte man, dass beide gleich sind, muss man lediglich die AssemblyFileVersion löschen.
Möchte man den Titel eines Diagramms aus einer Zelle holen, muss man einen kleinen Trick anwenden. Über den Dialog "Diagrammoptionen" lässt sich nur ein fester Text eingeben. Wenn man aber den Titel im Diagramm markiert und dann in der Eingabeleiste den Verweis eingibt, funktioniert das ganze.
Nach der Aktualisierung von Daten eines Pivot-Charts sind ie Formatierungen wie Farben der Balken etc. verloren. Dies liegt daran, weil das Diagramm komplett neu aufgebaut wird. Dies kann man umgehen, indem man die Einstellungen als benutzerdefinierten Diagrammtyp speichert und diesen dann dem Chart wieder zuweist. Ein Makro zur Aktualisierung der Daten eines Pivot-Charts ohne Verlust der Formatierung könnte dann so aussehen:
ActiveWorkbook.Sheets("Projektzeiten").PivotTables("PivotTable2").PivotCache.Refresh Application.Wait (Now + TimeValue("0:00:01")) Application.ActiveWorkbook.Charts(1).ApplyCustomType ChartType:=xlUserDefined, TypeName:="MyType" Application.ActiveWorkbook.Charts(1).HasPivotFields = False
Den Wait in Zeile 2 braucht er offensichtlich, da sonst die Aktualisierung noch nicht abgeschlossen ist.
Über Array-Formeln lassen sich Konstrukte wie das folgende erstellen:
{=MITTELWERT(WENN(ISTNV(C1:C3);"";C1:C3))}
Arrayformeln müssen mit STRG+UMSCHALT+EINGABE bestätigt werden (statt nur EINGABE). Die geschweiften Klammern müssen nicht eingegeben werden, sondern werden von Excel nach der Bestätigung mit STRG+UMSCHALT+EINGABE automatisch hinzugefügt. Klappt auch bei MIN, MAX und MEDIAN.
Mit dem SP1 spendiert Microsoft dem SQL Server 2005 Express zusätzlich die zwei Funktionen Reporting-Services und den Volltextindex des großen Bruders. Vorlagen für das Erstellen der Reports für Visual Studio gibt es mit dem Microsoft SQL Server 2005 Express Edition Toolkit SP1.
http://msdn.microsoft.com/vstudio/express/sql/download/
Unter http://msdnwiki.microsoft.com/en-us/mtpswiki/ms404855(VS.80).aspx bietet Microsoft ab sofort, zunächst als Beta-Version, ein Wiki an, das die MSDN-Dokumentation zu VS 2005 und .Net Framework 2.0 enthält. Das besondere dabei ist, dass durch die community Anmerkungen, Code-Beispiele etc. hinzugefügt werden können.
Bleibt abzuwarten, wie die Community sich hier beteiligt.
Jeder kennt das Problem. Man hat einen ellenlangen SQL-String und spätestens nach der dritten Klammer hat man den Überblick verloren, wenn allles in einer Zeile steht. Hier hilft ein kleines Tool weiter, das SQL-Strings, auch komplexe, übersichtlich formatiert. Das Tool gibt es als kostenlose Online-Version und als kostenpflichtige Offline-Version oder auch als API.
http://www.sqlinform.com/
Mit Hilfe der Eigenschaft UpdateBatchSize kann eingestellt werden, wieviele Update-Befehle beim Updaten eines Datasets in die Datenbank zusammengefasst werden sollen.
DataAdapter and Batch Updates. In the previous version of ADO.NET, when updating a database with changes from a DataSet, the Update method of a DataAdapter performs updates to the database one row at a time.
As the method iterates through the rows in the specified DataTable, it examines each DataRow to see if the row has been modified. If the row has been modified, the method calls the appropriate UpdateCommand, InsertCommand or DeleteCommand, depending on the value of the RowState property for that row. Every row update involves a network round-trip to the database.
In ADO.NET 2.0, the DataAdapter exposes an UpdateBatchSize property. Setting the property to a positive integer value causes updates to the database to be sent as batches of the specified size. For example, setting the UpdateBatchSize to 10 will group 10 separate statements and submit them as a single batch. Setting the UpdateBatchSize to 0 will cause the DataAdapter to use the largest batch size that the server can handle. Setting it to 1 disables batch updates as rows are sent one at a time.
Event Behavior Changes with Batch Updates. The DataAdapter class has two update-related events i.e. RowUpdating and RowUpdated. In previous versions of ADO.NET, and when batch processing is disabled, each of these events is generated once for each row processed. RowUpdating is generated before the update occurs, and RowUpdated is generated after the database update is completed.
When batch processing is enabled, multiple rows are updated in a single database operation. Therefore, only one RowUpdated event occurs for each batch, whereas the RowUpdating event occurs for each row processed.
When batch processing is disabled, the two events are fired with one-to-one interleaving where one RowUpdating event and one RowUpdated event fire for a row, then one RowUpdating and one RowUpdated event fire for the next row, until all of the rows are processed.
Projekte aus Visual Source Safe 2005 können mit Hilfe eines Konverters nach Team Foundation Server migriert werden. Dabei bleibt die Historie komplett erhalten. Eine Migration von Visual Source Safe 6.0 nach VSS 2005 kann über Backup / Restore erfolgen.
http://msdn2.microsoft.com/en-us/library/ms253060.aspx
|
Copyright © 2010 Thomas. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.
Pick a theme:
|
|