Rash thoughts about .NET, C#, F# and Dynamics NAV.


"Every solution will only lead to new problems."

Category .NET

In dieser Kategorie geht es um das Microsoft .NET Framework und damit zusammenhängende Technologien wie CLR, C#, ASP.NET, WCF, WF und WPF.

Wednesday, 8. November 2006


6,8 Millionen Visual Studio Express-Downloads in einem Jahr

Filed under: Visual Studio — Steffen Forkmann at 16:18 Uhr

Wie Dan Fernandez in seinem Blog schreibt wurde Visual Studio Express schon 6,8 Millionen mal kostenlos runtergeladen. Eine beeindruckende Zahl. Microsoft scheint dort ähnliche Strategien zu verfolgen wie Borland mit Turbo Pascal in der Anfangszeit – vertreue deine Tools unter den “Anfängern” und hoffe das wenn sie Profis sind die Tools lieb gewonnen haben und dann kaufen. Zumindest der erste Teil scheint schonmal aufgegangen zu sein.

Tuesday, 7. November 2006


.NET Framework 3.0 released

Filed under: .NET 3.0,msu solutions GmbH,Visual Studio,Windows Vista — Steffen Forkmann at 17:38 Uhr

Microsoft hat das .NET Framework 3.0 (englisch) als Final released. Bei Windows Vista ist .NET 3.0 dann auch vorinstalliert.

Es existieren folgende Downloads:

Tags: , , ,

Saturday, 4. November 2006


Eine überwachte Kopierfabrik (5)

Filed under: C#,Tools — Steffen Forkmann at 11:22 Uhr

Im fünften Teil meiner Serie möchte ich auf erweiterte Möglichkeiten der Konfiguration des Dienstes eingehen. Über die ApplicationSettings ist es in Visual Studio ganz einfach möglich Strings, Integer usw. als globale Anwendungseinstellungen (web.config bei ASP.NET – sonst app.config) abzuspeichern:

<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="userSettings" type="..."> <section name="DBCopyService.Properties.Settings" type="..." allowExeDefinition="MachineToLocalUser" requirePermission="false" /> </sectionGroup> </configSections> <userSettings> <DBCopyService.Properties.Settings> <setting name="ServerName" serializeAs="String"> <value>serverName</value> </setting> </DBCopyService.Properties.Settings> </userSettings> </configuration>

Der Zugriff auf die Einstellung “ServerName” erfolgt dann ganz einfach über Properties.Settings.Default.ServerName. Man kann sogar zur Laufzeit die Settings ändern und wieder abspeichern.

Wenn man jedoch komplexere Strukturen in den Einstellungen ablegen möchte, kommt man um etwas Code nicht mehr herum. Im folgenden Beispiel lege ich die neue Sektion “entrances” an, um dort dann beliebig viele Eingangsverzeichnisse überwachen zu lassen:

Eintrag in der app.config:

<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="DBCopyService"> <section name="entrances" type="DBCopyService.EntranceSection,DBCopyService" /> </sectionGroup> </configSections> <DBCopyService> <entrances> <entrance name="entrance1" path="C:\Eingang\" mailAddress="mail@server.de" /> <entrance name="entrance2" path="C:\Eingang2\" mailAddress="mail2@server.de" /> </entrances> </DBCopyService> </configuration>

Zugriff über Ableitung von ConfigurationElement, ConfigurationElementCollection und ConfigurationSection:

using System; using System.Collections.Generic; using System.Text; using System.Configuration; namespace DBCopyService { public sealed class EntranceElement : ConfigurationElement { /// <summary> /// Gets or sets the name. /// </summary> /// <value>The name.</value> [ConfigurationProperty("name", IsKey = true, IsRequired = true)] public string Name { get { return (string)base["name"]; } set { base["name"] = value; } } /// <summary> /// Gets or sets the mail address. /// </summary> /// <value>The mail address.</value> [ConfigurationProperty("mailAddress", IsRequired = true)] public string MailAddress { get { return (string)base["mailAddress"]; } set { base["mailAddress"] = value; } } /// <summary> /// Gets or sets the path. /// </summary> /// <value>The path.</value> [ConfigurationProperty("path", IsRequired = true)] public string Path { get { return (string)base["path"]; } set { base["path"] = value; } } } }
using System; using System.Collections.Generic; using System.Text; using System.Configuration; namespace DBCopyService { public sealed class EntranceCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new EntranceElement(); } protected override object GetElementKey( ConfigurationElement element) { return ((EntranceElement)element).Name; } public override ConfigurationElementCollectionType CollectionType { get { return ConfigurationElementCollectionType.BasicMap; } } protected override string ElementName { get{ return "entrance"; } } } }
using System; using System.Collections.Generic; using System.Text; using System.Configuration; namespace DBCopyService { public sealed class EntranceSection : ConfigurationSection { [ConfigurationProperty("", IsDefaultCollection = true)] public EntranceCollection Entrances { get { return (EntranceCollection)base[""]; } } } }

Mit Hilfe dieser Klassenstruktur (Element, Collection, Section) kann man nun bequem auf die Section zugreifen:

EntranceSection entranceSection = ConfigurationManager.GetSection("DBCopyService/entrances") as EntranceSection; foreach (EntranceElement element in entranceSection.Entrances) Console.WriteLine( string.Format("Path {0}, Mail {1}", element.Path, element.MailAddress));

Eine überwachte Kopierfabrik (4)

Filed under: C#,Tools — Steffen Forkmann at 11:00 Uhr

Im vierten Teil meiner kleinen Serie zur überwachten Kopierfabrik, soll es nun darum gehen den Kopiervorgang in einen anderen Thread auszulagern. Das Problem ist nämlich, dass der lang anhaltende Kopiervorgang sonst das Erkennen weiterer Dateisystem-Ereignisse verhindert und der Dienst für die Zeit des Kopierens “eingefroren” ist. Um nun den Kopiervorgang “parallel” zu starten, kann man in C# 2.0 den sogenannten BackgroundWorker benutzen. Dieser bietet auf ganz einfache Weise die Möglichkeit ein lang andauernden Vorgang in einen Hintergrundthread zu verlagern und über Events sogar Fortschrittsmeldungen nach Außen zu geben. Im speziellen Fall des Kopierens könnte man also einfach von BackgroundWorker ableiten:

using System; using System.Collections.Generic; using System.Text; using System.ComponentModel; using System.IO; using System.Diagnostics; namespace DBCopyService { /// <summary> /// This BackgroundWorker copies the file async /// from source to target /// </summary> public class BackgroundCopyWorker : BackgroundWorker { private string sourceFile; private string targetFile; public BackgroundCopyWorker (string sourceFile, string targetFile) : base() { this.sourceFile = sourceFile; this.targetFile = targetFile; DoWork += new DoWorkEventHandler(bcw_DoWork); RunWorkerCompleted += new RunWorkerCompletedEventHandler (bcw_RunWorkerCompleted); RunWorkerAsync(); // Start new Thread } void bcw_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { Trace.WriteLine(string.Format("{0} copied to {1}", sourceFile, targetFileName)); } void bcw_DoWork(object sender, DoWorkEventArgs e) { try { Trace.WriteLine(string.Format("Copy {0} to {1}", sourceFile, targetFile)); FileInfo SourceFile = new FileInfo(sourceFile); FileInfo TargetFile = new FileInfo(targetFile); SourceFile.CopyTo(TargetFile.FullName, true); } catch (Exception ex) { Trace.TraceError(ex.Message); } } } }

Das Starten eines asyncronen Kopiervorgangs erfolgt dann ganz einfach über:

new BackgroundCopyWorker(originalFileName, targetFileName);

Monday, 30. October 2006


Migration von Visual Source Safe (VSS) zum Team Foundation Server (TFS)

Filed under: msu solutions GmbH,Tools,Visual Studio — Steffen Forkmann at 10:52 Uhr

Steven Jean beschreibt in einem umfangreichen Artikel die Versionsverwaltungsfeatures des Team Foundation Server aus der Sicht von VSS-Nutzern. Er zeigt u.a. die veränderten Arbeitsabläufe und die neuen Sicherheitsfeatures die sich mit dem TFS ergeben. Eines der größten Vorteile aus meiner Sicht ist übrigens, dass beim Check-In die definierten Policies überprüft werden und so nur Code eingecheckt werden kann, der bestimmten selbstdefinierbaren Richtlinien entspricht.

Interessant in diesem Zusammenhang ist auch ein Channel 9 Video in dem John Lawrence, seines Zeichens Development Manager des “Visual Studio 2005 Team Foundation’s Source Code Management Teams”, interessante Anwendungsmöglichkeiten des Team Foundation Servers zeigt – zum Beispiel auch automatisch generierte RSS-Feeds mit den Bugmeldungen.

Tags: , , , ,

Friday, 27. October 2006


Eine überwachte Kopierfabrik (3)

Filed under: C#,Tools — Steffen Forkmann at 15:50 Uhr

Nachdem ich nun schon 2 kleinere Artikel zur überwachten Kopierfabrik geschrieben habe (Teil 1 und Teil 2), folgt nun der dritten Teil. Heute soll kurz gezeigt werden wie man mit C# ein Eingangsverzeichnis überwachen kann und dann bei Änderungen per Mail informiert wird.

using System.Net.Mail; ... fileSystemWatcher.Created += new FileSystemEventHandler(fileSystemWatcher_Created); ... void fileSystemWatcher_Created(object sender, FileSystemEventArgs e) { MailMessage mailMessage = new MailMessage(from,to); mailMessage.Subject = string.Format("EntranceWatcher: {0}",e.FullPath); mailMessage.Body = string.Format( "Die Datei {0} wurde eben in ein Eingangsverzeichnis kopiert.", e.FullPath); SmtpClient smtpClient = new SmtpClient(smtpServer); smtpClient.Send(mailMessage); }

Saturday, 21. October 2006


Eine überwachte Kopierfabrik (2)

Filed under: C#,Tools — Steffen Forkmann at 17:36 Uhr

Gestern habe ich über ein kleines Tool berichtet, dass wiederkehrende langwierige Kopierfunktionen für den Nutzer versteckt in den Hintergrund verlagert und so einen ganz deutlichen Performancegewinn darstellt.

Um das Tool auf dem Server effektiv nutzen zu können wird es natürlich als Windows Dienst ausgeliefert. Wie man aus seinem Projekt einen solchen Dienst macht, wird ganz ausführlich in einer Exemplarischen Vorgehensweise auf MSDN demonstriert.

Mit folgendem Code-Schnipsel kann man sogar das Tracing des Dienstes gleich auf das EventLog umleiten:

using System.Diagnostics; ... EventLogTraceListener eventlogListener = new EventLogTraceListener("DBCopyService"); Trace.Listeners.Add(eventlogListener); Trace.WriteLine("Tracing auf EvenLog");

Tracing in die Ereignisanzeige

Friday, 20. October 2006


Eine überwachte Kopierfabrik

Filed under: C#,Tools — Steffen Forkmann at 20:20 Uhr

Bei uns in der Firma haben wir das Problem, dass wir für Entwicklungstests oft große Navision-Datenbanken aus einem Original-Verzeichnis in unsere Testverzeichnisse auf dem Testserver kopieren müssen. Dies hat bisher immer sehr viel Zeit (bis zu 30min pro DB) in Anspruch genommen – Zeit in der man nur unproduktiv auf das Ende des Kopiervorgangs warten konnte. Mit Hilfe eines kleinen Tricks kann man diese Zeit jedoch für den Nutzer fast komplett auf Null reduzieren.

Wir haben jetzt folgende Verzeichnisstruktur (alles auf dem selben Server)

  • Original (hier liegen die Ausgangsdatenbanken)
  • Lager (dies ist ein überwachtes Zwischenverzeichnis)
  • Nutzer
    • Steffen
    • Maik

Die Idee ist nun, dass die Nutzer sich eine Datenbank bei Bedarf einfach aus dem Lager in ihren Nutzer-Ordner schieben. Dabei passiert auf dem Dateisystem ja kein Kopiervorgang – sondern nur ein sehr schneller Verschiebevorgang. Der Lager-Ordner wird jedoch von einem Mini-Tool überwacht. Dies hat den Vorgang registriert und kopiert nun im Hintergrund die Datenbank aus dem Originalverzeichnis ins Lager. Sobald dieser Vorgang abgeschlossen ist, kann der nächste Nutzer wieder schnell auf die DB im Lager zu greifen.

Nun zur Implementierung des Überwachungs-Tools in C#:

// Consolenstart static void Main(string[] args) { FDBWatcher fdbWatcher = new FDBWatcher(); Console.ReadLine(); } class FDBWatcher { private string warehousePath = @"C:\\Test\\Lager\\"; private string originalPath = @"C:\\Test\\Original\\"; private string targetEndingFilter = "*.fdb"; public FDBWatcher() { FileSystemWatcher fdbWatcher = new FileSystemWatcher( warehousePath, targetEndingFilter); fdbWatcher.EnableRaisingEvents = true; fdbWatcher.IncludeSubdirectories = false; fdbWatcher.Deleted += new FileSystemEventHandler(fdbWatcher_Deleted); Console.Write("FileSystem Watcher started"); } private void fdbWatcher_Deleted(object sender, FileSystemEventArgs e) { Console.WriteLine("File {0} deleted", e.FullPath); FileInfo oldFile = new FileInfo(e.FullPath); FileInfo originalFile = new FileInfo(originalPath + oldFile.Name); originalFile.CopyTo(oldFile.FullName); Console.WriteLine( "Copy {0} to {1}", originalFile, oldFile); } }

Monday, 16. October 2006


Navision das "überfleißige" Bienchen

Filed under: C#,Navision — Steffen Forkmann at 9:37 Uhr

Navision scheint auf “Lazy Evaluation” komplett zu verzichten und ganz fleißig jeden logischen Ausdruck bis zum Ende durchzurechnen.

Mit folgendem Beispiel kann man das leicht nachprüfen:

IF A AND B THEN MESSAGE('A and B'); ... PROCEDURE A@1000000001() : Boolean; BEGIN MESSAGE('A'); EXIT(FALSE); END; PROCEDURE B@1000000002() : Boolean; BEGIN MESSAGE('B'); EXIT(TRUE); END;

Wenn man diesen Code ausführt werden beide Messages (‘A’ und ‘B’) angezeigt, obwohl eigentlich nach Funktion A der Term A AND B schon als falsch ausgewertet werden kann. Wenn man selbiges Beispiel in C# aufschreibt wird übrigens nur A() ausgeführt:

if (A() && B()) MessageBox.Show("A and B"; ... bool A() { MessageBox.Show("A"); return false; } bool B() { MessageBox.Show("B"); return true; }

Ähnlich verhält es sich auch mit allen anderen logischen Ausdrücken – Navision rechnet bis ganz zum Ende alles durch.

Saturday, 14. October 2006


10 Tipps für erfolgreiche Software-Entwicklung

Filed under: .NET,Informatik,Navision — Steffen Forkmann at 12:56 Uhr

In der Softwarentwicklung steht man oft vor den selben Problemen, sodass es wichtig ist sich an bestimmte Punkte zu erinnern und diese dann zu beherzigen. In meinem Artikel “10 Tipps für erfolgreiche Software-Entwicklung” beschreibe ich wie man mit wenigen Schritten seine Produktivität stark erhöhen kann. 

Die Tipps im Überblick:

  1. Versuchen Sie mindestens eine 11 im Joel-Test zu erreichen.
  2. Arbeiten Sie nach Entwurfsmustern und dokumentieren Sie Ihre Arbeit mit der Angabe des Musters.
  3. Dokumentieren Sie Ihre Arbeit vor der Implementation.
  4. Arbeiten Sie bei schwierigen Aufgaben die buganfällig sind immer zu zweit.
  5. Haben Sie Spaß an Ihrer Arbeit.
  6. Nutzen Sie die Community.
  7. Arbeiten Sie klare Workflows für Ihre Entwicklung heraus.
  8. Nutzen Sie intern immer die neuesten Versionen Ihrer Produkte.
  9. Arbeiten Sie nach einem klaren Zeitplan – aber planen Sie Zeit für Katastrophen ein.
  10. Nutzen Sie ein internes Wiki um einmal erforschte Sachverhalte abzuspeichern.

 Genauere Erklärungen dazu finden Sie im Artikel.