[Journal - .NET Console on the Console]

.NET Console on the Console

Monday, November 14, 2005

I've started work on console application utilities, with a console app infrastructure as the ultimate goal in mind. Every console app should have easy access to the its environment, to the command line, including simple validation facilities. You can see how far I have progressed in the classes in Gregor.Core.Configuration.

Further ideas: any console application should be extensible with AddIns - the need is appearant, for example, in an application like the TextGen tool. Then, every console application should be scriptable as well. Again, TextGen is the perfect example.

The other day, I was thinking about how to best create a little tool that extracts links from an web document and downloads the target ressources to local disc. What would be the best way to structure the application? Should parsing be separate from the downloading code? How would such an application relate to my existing Downloader tool (which is part of the File Tools collection, available off the Downloads page), which so far is FTP-only?

I did not find satisfactory answers to these questions. One thing that made sense to me was to place the link extraction code, in a somewhat generalized way, into the Gregor.Core library. But the problem of how to factor (the word is a back formation from the verb refactor) the various pieces of functionality remained. UNIX makes it easy to for console apps to work together, and use shell scripts as glue. The Windows approach is to place things into DLLs, and have an application glue them together.

So how did I solve my problem? Given the following facts:

Therefore, I decided to implement my application as interpreted code:

// DownloadLinks.cs

UserCommand.LoadAssembly("Gregor.Inet.dll");

UserImport.Add("System");
UserImport.Add("System.Net");
UserImport.Add("Gregor.Core");
UserImport.Add("Gregor.Inet");

UserOption.Const = false;

cmdLine = UserCommand.GetCommandLine();
Check.ValueGreater(cmdLine.OperandCount, 0);

var sContent = NetUtil.ReadUrl(cmdLine.GetOperand(0));
var links = Parse.ExtractBetweenAll(sContent, "href=\"", "\"");

var wc = new WebClient();

downloadLink(sLink)
{
    var sFileName = getFileName(sLink);
    var sMsg = string.Concat("Downloading ", sLink, " to ", sFileName, " ...");
    Dev.Trace(sMsg);
    wc.DownloadFile(sLink, sFileName);
}

getFileName(var sLink)
{
    var sRet = sLink;
    // ... this works only with relative links to files so far
    sRet;
}

foreach(var sLink in links){
    downloadLink(sLink);
}

The code can be invoked like this:

NetConsole /file:DownloadLinks.cs http://peisker.net/journal.htm

This approach can be generalized to satisfy the requirements of both extensible and scriptable console applications mentioned above as well - .NET Console can serve as a command interpreter (aka, shell), and, if you will, as a generalized console application infrastructure.