Saturday, 4. November 2006
Nov 04
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);
Friday, 27. October 2006
Oct 27
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
Oct 21
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");

Friday, 20. October 2006
Oct 20
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
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
Oct 16
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.
Friday, 6. October 2006
Oct 06
Delegates gibt es schon in C#, aber mit dem Lambda Operator (=>) geht das nun kürzer.
Folgendes generisches Beispiel (bisher):
delegate T Func(T t);
Func funcDel = delegate(int x)
{
return x + x;
}
Console.WriteLine(funcDel(5));
-
delegate T Func(T t);
-
Func funcDel = delegate(int x)
-
{
-
return x + x;
-
}
-
Console.WriteLine(funcDel(5));
Äquivalent mit Lampda Operator:
Func lambda = x => x + x;
Console.WriteLine(lambda(5));
-
Func lambda = x => x + x;
-
Console.WriteLine(lambda(5));
Monday, 18. September 2006
Sep 18
Oftmals steht man im Navision vor dem Problem einen Report in einem bestimmten Druckerfach auszugeben. Dafür muss man jedoch die RawKind-Property des Druckerfachs wissen und im Report als PaperSourceFirstPage bzw. PaperSourceOtherPages oder über CurrReport.PaperSource einstellen. Leider gibt es im Navision keine einfache Möglichkeit diese Property auszulesen. Mit dem folgenden Stück C#-Code kann man sich jedoch alle installierten Drucker samt unterstützten Druckerfächern anziegen lassen:Â Â
using System.Drawing.Printing;
..
PrinterSettings ps = new PrinterSettings();
foreach (string name
in PrinterSettings.InstalledPrinters)
{
listBox1.Items.Add(name);
ps.PrinterName = name;
foreach (PaperSource paperSource
in ps.PaperSources)
listBox1.Items.Add(ps);
}
Tags:
C#,
msu-solutions-GmbH,
Navision
Thursday, 17. August 2006
Aug 17
Nini ist eine .Net Library mit welcher man besonders schnell hoch flexible Anwendungen mit Konfigurationsdateien erstellen kann. Die Anwendung ist denkbar einfach wie man im folgenden Beispiel sieht:
; MyApp.ini
[Logging]
File Name = MyApp.log
MessageColumns = 5
MaxFileSize = 40000000000000
Und der C# Code zum einlesen sieht folgendermasen aus:
using Nini.Config;
IConfigSource source =
new IniConfigSource("MyApp.ini");
string fileName =
source.Configs["Logging"].Get("File Name");
int columns =
source.Configs["Logging"].GetInt("MessageColumns");
long fileSize =
source.Configs["Logging"].GetLong("MaxFileSize");
Das war aber noch längst nicht alles. Noch mehr gibt es hier.
Sunday, 26. March 2006
Mar 26
Da es keine native Möglichkeit gibt ein Quellcode-Versionsverwaltungsprogramm in Microsoft Navision einzubinden, haben wir bei der msu solutions GmbH eine eigene Lösung zum Zugriff auf Visual Source Safe oder Subversion (SVN) implementiert. Die entstandene Lösung ist ein Hybrid aus C# 2.0 COM-Objekten und nativen Navision-Objekten.

Der allgemeine Arbeitsablauf gestaltet sich nun folgendermaßen:
- Eine Aufgabe aus dem internen Bug & Task Tracker ziehen.
- Statt dem klassischen “Design” im Object Designer einfach im internen Object Designer auf “Auschecken” klicken. Dadurch wird das Objekt im VSS ausgecheckt und die aktuelle Version neu ins Navision importiert und im Designer geöffnet.
- Nun kann man im Navision Quelltext Editor Änderungen vornehmen und evtl. weitere Objekte auschecken.
- Vor dem Einchecken auf “Compare” klicken. Dadurch wird ein Diff zwischen der bearbeiteten Version und der Version im VSS angezeigt. (Das Diff-Programm kann frei gewählt werden. Standardmäßig ist WinMerge eingestellt.)
- Im internen Object Designer auf die ausgecheckten Objekte filtern und die Objekte durch Klick auf “Einchecken” mit dem aus dem Bug & Task Tracker vorgegebenen Checkin-Kommentar ins VSS einchecken.
Als weiteres besonderes Feature ist die Versionsgeschichte zu nennen. Im internen Object Designer kann man einfach auf ein Objekt gehen und durch Druck auf “History” die Versionsgeschichte des Objektes aus dem Visual SourceSafe abrufen. Dort kann man die Checkin-Kommentare ansehen, Version-Pins versetzen und sich Diffs zwischen den verschiedenen Versionen anzeigen lassen.

Interessant ist auch die interne Suchen nach Objekten (und deren Versionen bzw. Differenz dazwischen) die mit einer bestimmten Aufgabe geändert wurden. So fällt das Portieren von Features zwischen verschiedenen Entwicklungszweigen wesentlich leichter.

So macht das Programmieren in Navision gleich viel mehr Spaß und die Versionsverwaltung ist damit fast so einfach wie im Visual Studio – da bleiben dann ja nur noch die beiden größten Navision Schwächen: Editor und Debugger 🙂
Tags:
C#,
com,
cvs,
Navision,
perforce,
quellcodeverwaltung,
source-safe,
subversion,
svn,
Tools,
visual-source-safe,
vss
Wednesday, 25. January 2006
Jan 25
In diesem Nightcast möchte Bernd Marquardt ein interessantes Thema aufgreifen. Er will in einer Stunde einen kleinen Sprach-Compiler entwickeln. Geplant sind ein kleine Einführung in Compilerbau und dann natürlich das Praktische also der Code, der notwendig ist, um einen eigenen Sprach-Compiler mit .NET zu entwickeln.