Shared

 

Shared source by placing a copy of a source file in you project may not sound like a great idea. In the right circumstances it can make sense, this collection of source files is intended to serve in those few cases.

  • ArgumentList.cs – Provides a simple means of collecting options like /name=value from the command-line arguments.
  • Check.cs – A static set of runtime assertions like Check.NotNull(value) and Check.Assert<TException>(bool)
  • Configuration.cs – An XSD validating configuration section that uses the XmlSerializer to deserialize the configuration section.
  • FileList.cs – Used to collect all the files in a folder or set of folders using a full file spec “.\src\*.csproj”
  • ProcessInfo.cs – Provides a class that gathers information about the current process without allowing exceptions to be raised externally.
  • QuickLog.cs – A very simple logging class for equally simple command-line utilities and applications.

As you can see most of these classes are for use primarily in command-line applications and utilities. Thus the primary reason for the copy/paste source inclusion is to avoid adding dependencies. Several of these are also included in the Library if the added dependency is acceptable.

 

QuickLog is an EXTREMELY basic implementation of a logging API. Easy to extend by implementation of an event but sufficient to use by itself for some needs. It’s own API can be used directly or all calls to System.Trace.Write(…) will also be directed to the current output log file. The log does not roll until the application is restarted at which time the old log is renamed to ‘.bak’ to maintain one historical log.

The implementation is very primitive relying entirely upon the system trace routines.  It basically creates a default log file and adds a TextWriterTraceLister to append to the file.  All API calls essentially just call the Trace.Write() api. 

Q: So why use this and not just directly use Trace.Write?

A1: Well for one if you litter your code with calls to the System.Diagnostics namespace your stuck with it.  By using QuickLog you can alway migrate to another logging implementation when the need arises.  BTW, it’s API is roughly equivelent to the Logging project on this site.

A2: Additionally calling Trace.Write requires you to also litter your code with String.Format() calls.  This may not seem like a bad idea until one generates an exception.  This basically changes your logging system into a liability instead of a debugging aid. 

A3: If that isn’t enough, Trace.Write has a performance penalty associated with it, especially if a process is monitoring debug messages.  It is possible for another process to deadlock your process while waiting on a call from the underlying Win32 api OutputDebugString() to return.  This lock is caused by the implementation details of these debug messages and the global named mutex they rely upon.

Based on the above comments, the need for an isolation between your code an a log api is clear.  Write one yourself or use this quick and dirty implementation as a starting point, but use something. 

For usage review the test case, you can find the code here:
http://csharptest.net/browse/src/Shared/QuickLog.cs

 

FileList is a simple file enumeration class that can be used to easily find sets of files. Provide it a list of directory and/or file names and simply let it figure it out. It will raise an event for custom filtering or has some simple attribute-level filtering built-in.

FileList files = new FileList(@"C:\Temp\*");
files.Add(@"C:\boot.ini");
files.Add(@"C:\*.bat");
files.RecurseFolders = true;
files.Add(@"C:\Windows\system32");
foreach (FileInfo file in files)
    Console.WriteLine(file.Name);

As demonstrated above, you just cram stuff into it and enumerate.

 

The shared XmlConfiguration utility contains a templated base class used to implement a basic System.Configuration.ConfigurationSection. The class simply uses an XmlSerializer for the type argument specified and deserializes while validating against an XSD file. It’s extremely easy to use as all you need is an xml serializable class to represent your configuration section. To declare the configuration section more easily I usually derive a new class to provide the type argument and use this ‘shell’ class’ type name in the configuration. Here is the most basic example:

class Config : XmlConfiguration
{
    public Config() : base() { }
}

This vastly simplifies declaring the section within the configuration file. Now embeding the section is nothing more than naming the above class:

<configsections>
    <section name="mySection" type="CSharpTest.Net.Library.Config, Library" />
</configsections>

Once this is done, simply add the root node “mySection” and populate with the xml described by your xml serializable class. The only piece missing now is the xsd, you may already have one or know how to write one. If you don’t then you can generate one by using the xsd.exe tool that comes with the .Net SDK. The convention is roughly like:

C:>"$(FrameworkSDKDir)\bin\xsd.exe" /nologo "/out:.\bin" ".\bin\Library.dll"

You can simply embed this as a resource into your application calling it with same name as the class T provided and of course keeping the .xsd extension. This should now give you a working integration and you read your configuration file easiest by simply calling “Config.ReadConfig(“mySection”);“.

Essentially this circumvents much of the system configuration mechanics and complexities to ease the development.  I frankly have always hated the System.Configuration namespace and all that it contains.  I suppose this is why I avoid it with this class.

 

I so often see numerous projects online that fail to validate input arguments in C#.  Back in the early days of C++ this was not only common, but often required by employers.  What happened?  Did we just become so lazy that we’d rather recieve a null reference exception or index out of range instead of actually checking input values? 

Reguardless of how we came to be here if your developing an API for external consumption it IS your responsibility to check arguments.  It really isn’t alot of work, and thus the reason I published a VERY small example of how to achieve this.  The code for Check.cs is published on code.google.com along with the test case.

 I use template methods on the various assertion routines (allowing type T to be inferred) so that I can use the value in the same line of code I make the assertion.  Instead of just passing a value, I simply pass the result of the assert call.  This allows code to look something like “this._myInfo = Check.NotNull(arginfo);”.  In this example I can set a member in the constructor at the same time validating that the argument was not null. 

Try it out and feel free to extend the class as your needs arise.

 

ArgumentList is a command-line program argument parser that exposes named items (i.e. /name=value or -name:value) and unnamed items in an easy to use collection format. I invariably rely on this utility when witting command-line tools. It’s usage is strait-forward, simply construction one with the array of arguments:

    string[] rawArgs = new string[] { "-x=y", "noname", "/novalue" };
    ArgumentList args = new ArgumentList(rawArgs);

    //"x" is defined and has value of "y":
    Assert.IsTrue(args.Contains("x"));
    Assert.AreEqual("y", args["x"].Value);
    //"/novalue" is defined:
    Assert.IsTrue(args.Contains("novalue"));
    //"noname" is not a switch:
    Assert.IsFalse(args.Contains("noname"));
    Assert.AreEqual(1, args.Unnamed.Count);
    Assert.AreEqual("noname", args.Unnamed[0]);

Then you can simply index the collection by name or use any of the other standard IDictionary methods to access it’s contents. The only additional item would be the ‘Unnamed’ collection that allows access to the un-switched arguments (not preceeded by ‘/’ or ‘-’). For more usage examples see the test code (and coverage!).

View the code at:

http://csharptest.net/browse/src/Shared/ArgumentList.cs

Updated: If your looking for a complete command-line solution that supports parsing arguments, displaying usage help, and invocation of commands see the article entitled:
Using the CommandInterpreter.