C# AppSettings: Launching Programs and Storing AppSettings

This article was originally posted at Programmer’s Ranch on 22nd March 2014.

Hi all! 🙂

Today we’re going to write a little program that can start other programs. For example, it might launch MS Word, or your favourite browser. From this we will learn how to actually start other programs using C#, and also how to add settings into an application configuration file so that they can easily be changed.

Start off by creating a new Console Application using your favourite IDE. Throw out any code already in Main(), and add this initial code:

Console.Title = "Launcher";

// TODO code goes here

Console.ReadLine();

Now, to start a program from our code, we need to use the Process class. To be able to use it, we need to add the following to our usings:

using System.Diagnostics;

Starting a program is really easy. All we need to do is replace our “TODO” comment with the following:

string filePath = @"C:\tools\notepad++\notepad++.exe";
Process.Start(filePath);

And sure enough, when we run our program, Notepad++ is opened as well:

csappsettings-notepad++

Let us now take this a step further. We can allow the user to type in the name of an application, and the corresponding application will be launched. We could do this using a switch statement as in “C# Basics: Command Interpreter Using Methods“. Or even better, we can use a Dictionary to store the relationship between application names and their path. First, add the following using at the top if it’s not there already (e.g. if you’re using SharpDevelop):

using System.Collections.Generic;

Next, our Dictionary, using the collection initialiser syntax as in “Morse Code Converter Using Dictionaries“:

            Dictionary<string, string> programs = new Dictionary<string, string>()
            {
                { "notepad++", @"C:\tools\notepad++\notepad++.exe" },
                { "firefox", @"C:\tools\firefox\firefox.exe" }
            };

We can now accept user input and launch the appropriate program. Replace the two lines we wrote earlier (which include the call to Process.Start()) with this:

            Console.Write("Enter program to launch: ");
            string programName = Console.ReadLine();
            if (programs.ContainsKey(programName))
            {
                string path = programs[programName];
                Process.Start(path);
                Console.WriteLine("{0} launched from {1}", programName, path);
            }
            else
                Console.WriteLine("Unknown program");

The user gives us the name of the program he wants to launch. If that name exists in our dictionary, we get the corresponding path, and then launch it as we did before. If we try this now, it works pretty nicely:

csappsettings-firefox

Although this works pretty well, it isn’t very flexible to have the program names hardcoded in your program code. Imagine you give this program to a friend. It wouldn’t be very useful if he could only launch Firefox and Notepad++. What if he wanted to be able to launch SharpDevelop as well? And maybe in future he might want to add VLC as well. It obviously isn’t convenient for you to have to change the code, recompile, and give him an updated program each time.
One option could be to store these program settings in a file and read it, but .NET provides us with a simpler option that exists specifically for this kind of scenario. .NET applications can optionally come with an application configuration file, which is usually called App.config. In fact, if, like me, you’re using SharpDevelop 5 Beta 2, you should have one already (otherwise just add an Application Configuration File to your project):

csappsettings-appconfig

When you build the application, App.config gets renamed to the name of the executable, plus a “.config”, and is stored in the same folder:

csappsettings-appconfig2

In this App.config file, under the <configuration> node, we can add an <appSettings> node and store our settings. The settings have a key, which is a name that identifies them, and a value which is the value of the setting. Ours will be like this:

    <appSettings>
        <add key="notepad++" value="C:\tools\notepad++\notepad++.exe" />
        <add key="firefox" value="C:\tools\firefox\firefox.exe" />
    </appSettings>

With this done, we can now rewrite our program to use these settings. First, we need to add a reference to System.Configuration. To do this, right click on the name of the project in Solution Explorer, and select “Add Reference”:

csappsettings-addreference1

In the “Add Reference” window, locate “System.Configuration” and then click “OK”.

Next, add the following using statement at the top:

using System.Configuration;

We can now use ConfigurationManager to obtain our app settings, like this:

        public static void Main(string[] args)
        {
            Console.Title = "Launcher";
           
            string firefoxPath = ConfigurationManager.AppSettings["firefox"];
            Console.WriteLine(firefoxPath);
           
            Console.ReadLine();
        }

…And here’s what we see when we run this:

csappsettings-read-appsettings

So now, all we need to do is let the user tell us which program he wants to launch, and find it in the AppSettings:

        public static void Main(string[] args)
        {
            Console.Title = "Launcher";
           
            Console.Write("Enter program to launch: ");
            string programName = Console.ReadLine();
           
            string path = ConfigurationManager.AppSettings[programName];
            if (path == null)
                Console.WriteLine("Unknown program.");
            else
            {
                Process.Start(path);
                Console.WriteLine("{0} launched from {1}", programName, path);
            }
           
            Console.ReadLine();
        }

The only thing worth noting here is that if the specified key does not exist in the AppSettings, retrieving that key via ConfigurationManager.AppSettings[] returns null, allowing us to take appropriate action in that case.

So now, when you give this program to a friend, he can just add the following line in the CsAppSettings.exe.config file that conveniently comes with the program:

        <add key="fiddler" value="C:\tools\fiddler2\Fiddler.exe" />

…and without further ado, he can now launch Fiddler as well:

csappsettings-fiddler

Wonderful! 🙂

In this article, we learned how to start another program from our code, and we also learned how to work with application settings in an application configuration file.

Storing your application settings in an App.config file is convenient because they can be tweaked as needed, without having to recompile your program. These kinds of settings are best suited for settings that don’t change frequently, so you just set them when you need them, and forget about them. In the next article, we’ll learn about another kind of settings that are great for storing stuff like user preferences which can potentially change a lot.

Computing File Hashes in C#

This article was originally posted at Programmer’s Ranch as “C# Security: Computing File Hashes” on 2nd May 2014, which was the blog’s first anniversary. In this version of the article, I’ve removed anniversary references and made other slight edits where they were needed.

In this article, we’re going to learn a little about hashing: what it does, and how to use it to verify the integrity of a downloaded file (which is just one application where it is useful).

We’ve already seen seen in “C# Security: Securing Passwords by Salting and Hashing” that a hash function transforms an input string into a totally different piece of data (a hash):

cspwsec-hashfunc-1

If you make even a slight change to the input, such as changing the first character from uppercase to lowercase, you get a totally different output:

cspwsec-hashfunc-2

Also, if you use a decent hash function (i.e. not MD5), it is normally not possible to get the input string from the hash.

In today’s article, we’re going to use hashes for something much simpler than securing passwords. We’re going to hash the content of files, and then use that hash to check whether the file changed. Since I haven’t been very impressed with SharpDevelop 5 Beta, I’m going to ditch it and use Visual Studio 2013 instead. You can use whatever you like – SharpDevelop, Visual Studio Express for Desktop, or maybe even MonoDevelop.

Create a new Console Application, and add the following at the top:

using System.Security.Cryptography;

This will allow you to use a variety of hash functions, which all derive from the HashAlgorithm class.

We’ll also need a little helper function to convert our hashes from a byte array to a string, so that they may be displayed in hex in the command line. We’ll use the following, which is a modified version of the Hash() method from “C# Security: Securing Passwords by Salting and Hashing“:

        public static string ToHexString(byte[] bytes)
        {
            StringBuilder sb = new StringBuilder();
            foreach (byte b in bytes)
            sb.Append(b.ToString("x2").ToLower());

            return sb.ToString();
        }

Now, let’s create a text file in the same folder as our .sln file and name it “test.txt”, and put the following lyrics from the Eagles’ “Hotel California” in it:

So I called up the Captain,
"Please bring me my wine"
He said, "We haven't had that spirit here since nineteen sixty nine"
And still those voices are calling from far away,
Wake you up in the middle of the night
Just to hear them say...

Let’s read that file into memory. First, we need to add the following

using System.IO;

We can now read the contents of the file into a string:

string fileContents = File.ReadAllText(@"../../../test.txt");

…and quite easily compute the hash of those contents:

            using (HashAlgorithm hashAlgorithm = SHA256.Create())
            {
                byte[] plainText = Encoding.UTF8.GetBytes(fileContents);
                byte[] hash = hashAlgorithm.ComputeHash(plainText);
                Console.WriteLine(ToHexString(hash));
            }

            Console.ReadLine();

Note that I’m using SHA256 as the hash function this time – it’s a lot more robust than MD5. If you check the documentation for the HashAlgorithm class, you can find a bunch of different hash algorithms you can use. As it is, we get the following output:

cshashfile-output-1

Now, let’s see what happens if your little toddler manages to climb onto your keyboard and modify the file. Let’s remove the first character in the file (the initial “S”) – that might be within a toddler’s ability – and save the file. When we rerun the program, the output is quite different:

cshashfile-output-2

And here we have already seen how hashing gives us the means to verify a file’s integrity, or in other words, check whether it has been tampered with. In fact, popular Linux distributions such as Ubuntu distribute MD5 hashes for the files they release, so that the people who can download them can check that they are really downloading the file they wanted, and not some weird video of goats yelling like humans:

cshashfile-ubuntu-hashes

So let’s actually see this in action. After downloading an Ubuntu distribution, let’s change the filename to that of the Ubuntu file we downloaded, and the hash algorithm to MD5:

            string fileContents = File.ReadAllText(@"../../../../ubuntu-14.04-desktop-amd64.iso");

            using (HashAlgorithm hashAlgorithm = MD5.Create())

Now, let’s try to compute a hash of the Ubuntu file:

cshashfile-out-of-memory

Oops! We tried to read a ~1GB file into memory, and that’s a pretty stupid thing to do. Unless you’ve got a pretty awesome computer, you’ll see the memory usage spike until you get an OutOfMemoryException, as above. And even if you do have a pretty awesome computer, you shouldn’t load an entire massive file just to perform an operation on its contents.

In one of my first articles at Programmer’s Ranch, “C#: Working with Streams“, I explained how you could read a file bit by bit (e.g. line by line) and work on those parts without having to have the entire file in memory at any one time. And quite conveniently, the hash algorithms have a variant of the ComputeHash() method that takes a stream as a parameter.

So let’s change our code as follows:

        static void Main(string[] args)
        {
            using (FileStream fs = File.OpenRead(@"../../../../ubuntu-14.04-desktop-amd64.iso"))
            using (HashAlgorithm hashAlgorithm = MD5.Create())
            {
                byte[] hash = hashAlgorithm.ComputeHash(fs);
                Console.WriteLine(ToHexString(hash));
            }

            Console.ReadLine();
        }

And let’s run it:

cshashfile-streamed-hash

There are a few things to note from the output:

  • It computes pretty quickly, despite the fact that it’s going through a ~1GB file.
  • Memory levels remain at a pretty decent level (in fact the memory used by the program is negligible).
  • The output matches the first hash in the list of hashes on the Ubuntu webpage (in the background of the above screenshot).

In this article, we revisited the concept of hashing, and learned the following:

  • There are several different hash algorithms provided by .NET that you can use, including MD5, SHA256, and others.
  • A hash gives you a way to verify whether a file has been tampered with.
  • Streaming provides the ability to process large files quickly and with very little memory overhead.