Category Archives: Software development

Bypassing a Login Form using SQL Injection

This article was originally posted as “C# Security: Bypassing a Login Form using SQL Injection” on 5th January 2014 at Programmer’s Ranch. The article is based on ASP .NET Web Forms and ADO .NET, and the code example was originally written using Visual Studio Express for Web 2013 and SQL Server 2012 Express. This updated version removes references to particular software versions, adds syntax highlighting, and includes other simple edits where necessary.

In this article, we’re going to learn about SQL injection. We’ll use it to bypass a login form on a website, and you’ll see just how easy it is. Despite its simplicity, this article is going to be a little bit long – because we’ll need to set up a simple login form with a database that we can then use to try out the SQL injection. Naturally, you should never try out these types of attacks on someone else’s website; so when you want to learn something in practice, set up a vulnerable system of your own.

To demonstrate SQL injection, we’re going to be using ASP .NET (for the web form) and SQL Server (for the database). However, SQL injection is not tied to any technology in particular, so you could, for example, use PHP and MySQL instead. You are expected to know a little something about databases (SQL) and websites, although rest assured that there’s nothing complicated in this article.

Setting up the database

sqlinj-newdatabase

In order to create and set up our database, we’ll need to use SQL Server Management Studio. Launch it, and from the Object Explorer on the left, right click on the Databases node, and click on “New Database…”. Enter a name for your database (I’m using “sqlinjection”) and click OK.

sqlinj-newquery

You should now be able to right click on the newly created database and select “New Query”. This brings up a text editor where you can enter and run queries against the database. Enter the following script into this editor:

create table users (
    id int not null primary key identity(1,1),
    username varchar(50) not null,
    password varchar(50) not null
);

…and press F5 to execute it:

sqlinj-createtable

You should now have your users table with an id field as well as the username and password. Now, replace the script with the following:

insert into users(username, password)
values('hankmarvin', 'theshadows');

Press F5 to insert a new row where the username is “hankmarvin” and the password is “theshadows”. The id column should be filled automatically since we are using an IDENTITY on that column. Note that in this case we’re storing a password as cleartext for simplicity, but this is never a good idea – see my article “Securing Passwords by Salting and Hashing” if you don’t know why.

Creating the login form

In Visual Studio, go on File -> New Website… and create a new project of type ASP .NET Empty Web Site:

sqlinj-newproject

Next, right click on the project in Solution Explorer, and select Add -> Add New Item…, and then pick Web Form from the list of templates. Leave the name as Default.aspx.

Set up the markup in Default.aspx so that it looks like this:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            Username: <asp:TextBox ID="usernameField" runat="server" />
        </div>
        <div>
            Password: <asp:TextBox ID="passwordField" runat="server" />
        </div>
        <div>
            <asp:Button ID="loginButton" runat="server" Text="Login" OnClick="loginButton_Click" />
        </div>
        <div>
            <asp:Label ID="resultField" runat="server" />
        </div>
    </form>
</body>
</html>

It’s not wonderful HTML, and not exactly pretty, but it’s the simple login form that we need. You can see the result by pressing F5 to launch the project in your web browser:

sqlinj-loginform

Next, go into your webpage’s codebehind file (that would be Default.aspx.cs). Add the following statement near the top:

using System.Data.SqlClient;

Add the following event handler that actually takes care of the logic for logging in (your actual connection string may vary depending on how you installed SQL Server – see this if you run into issues):

    protected void loginButton_Click(object sender, EventArgs e)
    {
        String connStr = @"Data Source=localhost\SqlExpress;Initial Catalog=sqlinjection;Integrated Security=True;";
        String username = this.usernameField.Text;
        String password = this.passwordField.Text;
        String query = "select count(*) from users where username = '" + username
            + "' and password = '" + password + "'";

        try
        {
            using (SqlConnection conn = new SqlConnection(connStr))
            {
                conn.Open();

                using (SqlCommand command = new SqlCommand(query, conn))
                {
                    int result = (int)command.ExecuteScalar();
                    if (result > 0)
                        resultField.Text = "Login successful.";
                    else
                        resultField.Text = "Login failed! Go away!";
                }
            }
        }
        catch(Exception ex)
        {
            resultField.Text = ex.Message;
        }
    }

SQL Injection

You can now press F5 and test out the login form. If you enter the correct credentials, which are “hankmarvin” for username and “theshadows” as the password, then you should see the message “Login successful.” just below the form. For any other input, the login will fail.

It should be pretty evident that the code in loginButton_Click is constructing dynamic SQL based on the credentials provided. So for the correct credentials, this would build the SQL string:

select count(*) from users where username = 'hankmarvin' and password = 'theshadows'

The weakness in this is that we can write whatever we want into the username and password fields, and they’ll be included in the SQL query. Let’s see what happens when we use the following input in the password field:

' OR 1=1 --

Using this, we are logged in just fine:

sqlinj-injected-sql

Oops! What just happened here? If we take a look at the dynamic SQL that is being constructed, it becomes clear:

select count(*) from users where username = '' and password = '' OR 1=1 --'

The stuff we entered in the password field is closing off the SQL string (with the apostrophe at the beginning) and is adding a condition that will always be true (1=1). A comment (–) at the end gets rid of the remaining SQL, in this case a closing apostrophe. The query’s WHERE clause can now be read as follows:

((username = '') AND (password = '')) OR 1=1

Well, it turns out that 1=1 is always true, so the query ends up returning every row in the database. The count is greater than zero, and so the login is successful, even though we didn’t actually provide valid credentials.

Prepared Statements

The correct way to fight SQL injection is to use prepared statements. This means that the event handler changes as follows:

    protected void loginButton_Click(object sender, EventArgs e)
    {
        String connStr = @"Data Source=localhost\SqlExpress;Initial Catalog=sqlinjection;Integrated Security=True;";
        String username = this.usernameField.Text;
        String password = this.passwordField.Text;
        String query = "select count(*) from users where username = @username and password = @password";

        try
        {
            using (SqlConnection conn = new SqlConnection(connStr))
            {
                conn.Open();

                using (SqlCommand command = new SqlCommand(query, conn))
                {
                    command.Parameters.Add(new SqlParameter("@username", username));
                    command.Parameters.Add(new SqlParameter("@password", password));

                    int result = (int)command.ExecuteScalar();
                    if (result > 0)
                        resultField.Text = "Login successful.";
                    else
                        resultField.Text = "Login failed! Go away!";
                }
            }
        }
        catch(Exception ex)
        {
            resultField.Text = ex.Message;
        }
    }

Instead of building dynamic SQL, we insert named placeholders, such as @username, to stand in for parameters in the query. We then provide these values via the SqlCommand‘s Parameters property, where the values are paired up with the corresponding parameter names. Since these parameters are strongly typed, things like escaping apostrophes in strings are handled automatically, and so users can’t inject SQL via input fields.

In fact, if you try the same SQL injection attack as above, you’ll see that it doesn’t work any more:

sqlinj-injection-failed

Summary

As we have seen in this article, SQL injection is a really simple technique that can be used to breach security in vulnerable websites and applications. Bypassing login forms is only one of many things you can do with SQL injection, which is so dangerous that it has topped the OWASP Top 10 Risks for years.

To protect against SQL injection, use prepared statements to provide strongly-typed parameters in your SQL queries, and avoid dynamic SQL built directly by concatenating strings.

Securing Passwords by Salting and Hashing

This article was originally posted as “C# Security: Securing Passwords by Salting and Hashing” on 11th November 2013 at Programmer’s Ranch. This republished version is slightly edited. Although using silly passwords and the MD5 hash function is not recommended, they are used in this article to illustrate the point more easily.

Password security is often quite challenging to understand for those who are new to it (I’ve been there too, as you can see from my question about salting on StackOverflow). In this article, I am hoping to make this fascinating topic a little easier to understand. We’ll be covering two important techniques called hashing and salting. Although passwords are typically stored in a database, we’ll be using a C# dictionary to keep it simple.

Clear Text Passwords

To get started, create a new Console Application. Add the following near the top, so that we can use dictionaries:

using System.Collections.Generic;

Just inside your class Program, before your Main() method, add the following dictionary to store our users and their corresponding passwords (see “Morse Code Converter Using Dictionaries” if this seems in any way new to you):

        public static Dictionary<string, string> users = new Dictionary<string, string>()
        {
            { "johnny", "password" },
            { "mary", "flowers" },
            { "chuck", "roundhousekick" },
            { "larry", "password123" }
        };

It is now pretty simple to add a method that can check whether a given username and password result in a successful login:

        public static bool Login(string username, string password)
        {
            if (users.ContainsKey(username) && users[username] == password)
                return true;
            else
                return false;
        }

This code first checks that the username actually exists in the dictionary, and then checks whether the corresponding password matches.

We can now test this code by replacing the contents of Main() with the following code:

        public static void Main(string[] args)
        {
            Console.Write("Username: ");
            string username = Console.ReadLine();
          
            Console.Write("Password: ");
            Console.ForegroundColor = ConsoleColor.Black;
            string password = Console.ReadLine();
            Console.ResetColor();
          
            bool loggedIn = Login(username, password);
            if (loggedIn)
                Console.WriteLine("You have successfully logged in!");
            else
                Console.WriteLine("Bugger off!");
          
            Console.ReadLine();
        }

Notice that when requesting the password, we’re setting the console’s text colour to black. The console’s background colour is also black, so the password won’t show as you type, fending off people trying to spy it while looking over your shoulder.

Press F5 to try it out:

cspwsec-naive-output

Awesome – we have just written a very simple login system.

The problem with this system is that the passwords are stored as clear text. If we imagine for a moment that our usernames and passwords were stored in a database, then the actual passwords can easily be obtained by a hacker gaining illegal access to the database, or any administrator with access to the database. We can see this by writing a simple method that shows the users’ data, simulating what a hacker would see if he managed to breach the database:

        public static void Hack()
        {
            foreach (string username in users.Keys)
                Console.WriteLine("{0}: {1}", username, users[username]);
        }

We can then add the following code just before the final Console.ReadLine() in Main() to test it out:

Console.WriteLine();
Hack();

This gives us all the details, as we are expecting:

cspwsec-breach-cleartext

This isn’t a nice thing to have – anyone who can somehow gain access to the database can see the passwords. How can we make this better?

Hashing

One way is to hash the passwords. A hash function is something that takes a piece of text and transforms it into another piece of text:

cspwsec-hashfunc-1

A hash function is one-way in the sense that you can use it to transform “Hello” to “8b1a9953c4611296a827abf8c47804d7”, but not the other way around. So if someone gets his hands on the hash of a password, it doesn’t mean that he has the password.

Another property of hash functions is that their output changes considerably even with a very small change in the input. Take a look at the following, for instance:

cspwsec-hashfunc-2

You can see how “8b1a9953c4611296a827abf8c47804d7” is very different from “5d41402abc4b2a76b9719d911017c592”. The hashes bear no relationship with each other, even though the passwords are almost identical. This means that a hacker won’t be able to notice patterns in the hashes that might allow him to guess one password based on another.

One popular hashing algorithm (though not the most secure) is MD5, which was used to produce the examples above. You can find online tools (such as this one) that allow you to compute an MD5 hash for any string you want.

In order to use MD5 in our code, we’ll need to add the following statement near the top of our program code:

using System.Security.Cryptography;

At the beginning of the Program class, we can now create an instance of the MD5 class to use whenever we need:

private static MD5 hashFunction = MD5.Create();

If you look at the intellisense for MD5, you’ll see that it has a ComputeHash() method, which returns an byte array, rather than a string:

cspwsec-md5-computehash

We’re going to do some string work, so add the following near the top:

using System.Text;

Let’s write a little helper method to hash our passwords, using strings for both input and output:

        public static string Hash(String input)
        {
            // code goes here
        }

In this method, the first thing we need to do is convert the input string to a byte array, so that ComputeHash() can work with it. This is done using the System.Text.Encoding class, which provides several useful members for converting between strings and bytes. In our case we can work with the ASCII encoding as follows:

byte[] inputBytes = Encoding.ASCII.GetBytes(input);

We can then compute the hash itself:

byte[] hashBytes = hashFunction.ComputeHash(inputBytes);

Since we don’t like working with raw bytes, we then convert it to a hexadecimal string:

StringBuilder sb = new StringBuilder();
foreach(byte b in hashBytes)
sb.Append(b.ToString("x2").ToLower());

The “x2” bit converts each byte into two hexadecimal characters. If you think about it for a moment, hexadecimal digits are from 0 to f (representing 0-15 in decimal), which fit into four bits. But each byte is eight bits, so each byte is made up of two hex digits.

Anyway, after that, all we need to do is return the string, so here’s the entire code for the method:

        public static String Hash(String input)
        {
            byte[] inputBytes = Encoding.ASCII.GetBytes(input);
            byte[] hashBytes = hashFunction.ComputeHash(inputBytes);
          
            StringBuilder sb = new StringBuilder();
            foreach(byte b in hashBytes)
                sb.Append(b.ToString("x2").ToLower());
          
            return sb.ToString();
        }

We can now change our database to use hashed passwords:

        public static Dictionary<string, string> users = new Dictionary<string, string>()
        {
            { "johnny", Hash("password") },
            { "mary", Hash("flowers") },
            { "chuck", Hash("roundhousekick") },
            { "larry", Hash("password123") }
        };

In this way, we aren’t storing the passwords themselves, but their hashes. For example, we’re storing “5f4dcc3b5aa765d61d8327deb882cf99” instead of “password”. That means we don’t store the password itself any more (if you ever signed up to an internet forum or something, and it told you that your password can be reset but not recovered, you now know why). However, we can hash any input password and compare the hashes.

In our Login() method, we now change the line that checks username and password as follows:

if (users.ContainsKey(username) && users[username] == Hash(password))

Let’s try this out (F5):

cspwsec-hash-output

When the user types “johnny” as the username and “password” as the password, the password is hashed, giving us “5f4dcc3b5aa765d61d8327deb882cf99”. Since the passwords were also stored as hashes in our database, it matches. In reality our login is doing the same thing as it was doing before – just that we added a hash step (a) when storing our passwords and (b) when receiving a password as input. Ultimately the password in our database and that entered by the user both end up being hashes, and will match if the actual password was the same.

How does this help us? As you can see from the hack output (last four lines in the screenshot above), someone who manages to breach the database cannot see the passwords; he can only get to the hashes. He can’t login using a hash, since that will in turn be hashed, producing a completely different value that won’t match the hash in the database.

Although hashing won’t make the system 100% secure, it’s sure to give any potential hacker a hard time.

Salting

You may have noticed that in the example I used, I had some pretty dumb passwords, such as “password” and “password123”. Using a dictionary word such as “flowers” is also not a very good idea. Someone may be able to gain access to one of the accounts by attempting several common passwords such as “password”. These attempts can be automated by simple programs, allowing hackers to attempt entire dictionaries of words as passwords in a relatively short period of time.

Likewise, if you know the hash for common passwords (e.g. “5f4dcc3b5aa765d61d8327deb882cf99” is the hash for “password”), it becomes easy to recognise such passwords when you see the expected hash. Hackers can generate dictionaries of hashes for common passwords, known as rainbow tables, and find hashes for common words used as passwords.

We can combat such attacks by a process known as salting. When we compute our hashes, we add some string that we invent. This means changing the first line of our Hash() function as follows:

byte[] inputBytes = Encoding.ASCII.GetBytes("chuck" + input);

Both the database password and the one entered by the user will be a hash of “chuck” concatenated with the password itself. When the user tries to login, it will still work, but look at what happens now:

cspwsec-salt-output

The login worked, but the hashes have changed because of the salt! This means that even for a password as common as “password”, a hacker cannot identify it from the hash, making rainbow tables much less effective.

Summary

This article described how to store passwords securely. It started off by doing the easiest and worst thing you can do: store them as clear text. A hash function was subsequently introduced, to transform the passwords into text from which the password cannot be retrieved. When a user logs in, the hash of the password he enters is compared with the password hash stored in the database.

Finally, the hashes were salted, by adding an arbitrary piece of text to them, in order to transform the hashes into different values that can’t be used to identify common passwords.

Additional Notes

It is interesting to note that with hashes, it does not matter how long your password is. The hash is typically fixed-length (depending on the hash function you use). So if you create an account on some airline’s website and it tells you that your password is too long because they have some maximum limit… well, they don’t know what they are doing.

Hashing and salting make password storage a lot more secure. The next level is using a slow hash algorithm with a work function. You can read about this in my followup article, “Secure Authentication with BCrypt“.

Consistent Hashing in Akka .NET

The source code for this article is available at the Gigi Labs BitBucket repository.

Routers

In Akka .NET, a router is like a load balancer. It is a special actor that does not handle messages itself, but passes them on to other actors who can handle them. For this reason routers are the only kind of actor that can deal with several messages concurrently (whereas normal actors process messages sequentially, one by one).

The way routers forward messages to handling actors depends on the type of router you use. Some common routing strategies include broadcast, round robin, and random. In this article, we will deal with the ConsistentHashing router. Consistent hashing means that messages with the same (arbitrarily defined) key are always handled by the same actor.

Another important distinction between routers is that they fall under two categories: Group routers and Pool routers. “Pool” means the same as in the context of “Thread Pool” or “Connection Pool”: it is a dynamic set of resources that can adaptively grow and shrink as needed. A Pool router creates the actors that it will forward messages to for handling, and as such, it also supervises them. Group routers, on the other hand, passed a set of actors that are created beforehand. As such the handling actors are fixed in number and detached from the router; the Group router does not supervise them and often does not know when they die. For this reason Pool routers are preferred for most use cases.

There is a lot more to be said about routers. However, this section is intended only as a brief background. For more comprehensive references, check the links in the Further Reading section.

Consistent Hashing Example with Currency Pairs

In the financial industry, currency exchange is defined in terms of a currency pair, such as EUR/USD. This currency pair has a price, such as 1.1087. This means that 1 Euro is worth 1.1087 US Dollars. The currency exchange market is very volatile, and these prices can change several times per second.

In our example, we will be generating fictitious currency prices. We would like to have a pool of actors to handle these price updates. We would also like each currency pair to be always be handled by the same actor.

As always, we first need to install the Akka NuGet package:

Install-Package Akka

Then, in our Main() method, we will first add some trivial setup code:

            Console.Title = "Akka .NET Consistent Hashing";

            var random = new Random();
            var currencyPairs = new string[]
            {
                "EUR/GBP",
                "USD/CAD",
                "NZD/JPY",
                "EUR/USD",
                "USD/JPY",
                "NZD/EUR"
            };

Our program logic goes like this:

            using (var actorSystem = ActorSystem.Create("MyActorSystem"))
            {
                var pool = new ConsistentHashingPool(3);
                var props = Props.Create<CurrencyPriceChangeHandlerActor>()
                    .WithRouter(pool);
                var router = actorSystem.ActorOf(props, "MyPool");

                for (int i = 0; i < 20; i++)
                    SendRandomMessage(router, random, currencyPairs);

                Console.ReadLine();
            }

Here we’re setting up a Pool router using the Consistent Hashing strategy. A pool of 3 actors will be created, supervised by the router. We can send a message to the router as we would with any other actor, but it will actually be handled by one of its child actors.

The child actors are of type CurrencyPriceChangeHandlerActor. This type of actor simply writes the received message to the console, along with its own path so that we can distinguish between the child actors. The path is dynamically generated by the Pool router and we have no control over it.

    public class CurrencyPriceChangeHandlerActor
        : TypedActor, IHandle<CurrencyPriceChangeMessage>
    {
        public CurrencyPriceChangeHandlerActor()
        {
            
        }

        public void Handle(CurrencyPriceChangeMessage message)
        {
            Console.WriteLine($"{Context.Self.Path} received: {message}");
        }
    }

The message handled by this type of actor is a simple combination of currency pair and price. In line with best practices, the message is immutable by design. More importantly, it implements IConsistentHashable. This allows us to provide a key that will be used for the consistent hashing algorithm. In our case, the key is the currency pair.

    public class CurrencyPriceChangeMessage : IConsistentHashable
    {
        public string CurrencyPair { get; }
        public decimal Price { get; }

        public object ConsistentHashKey
        {
            get
            {
                return this.CurrencyPair;
            }
        }

        public CurrencyPriceChangeMessage(string currencyPair, decimal price)
        {
            this.CurrencyPair = currencyPair;
            this.Price = price;
        }

        public override string ToString()
        {
            return $"{this.CurrencyPair}: {this.Price}";
        }
    }

Note: this is just one of three ways how we can specify the key to use with consistent hashing. Refer to the documentation for more information.

All we have left is the implementation of SendRandomMessage(). It picks a random currency pair and a random price, and sends a message. It also introduces a random delay between each message. Without this delay, you’ll see a lot of the same currency pairs in sequence.

        private static void SendRandomMessage(IActorRef router, Random random,
            string[] currencyPairs)
        {
            var randomDelay = random.Next(100, 1500);
            var randomCurrencyId = random.Next(0, currencyPairs.Length);
            var randomPrice = Convert.ToDecimal(random.NextDouble());

            var currencyPair = currencyPairs[randomCurrencyId];

            var message = new CurrencyPriceChangeMessage(
                currencyPair, randomPrice);
            router.Tell(message);

            Thread.Sleep(TimeSpan.FromMilliseconds(randomDelay));
        }

Here’s what we get when we run the program:

akkanet-consistenthashing-output

You can see how although all three handling actors are in use, there is a direct correspondence between the currency pair and the actor that handles it. For example, USD/CAD is always handled by actor $c, whereas NZD/EUR is always handled by actor $b. This is what is implied by consistent hashing.

As far as I can tell, control of which actors handle which keys is up to the router. I would have liked to, for instance, create an actor to specifically handle each currency pair. But I don’t think that is possible, even with Group routers (correct me if I’m wrong). Just let the router worry about how to allocate the keys to the actors.

Further Reading

Extracting Zipped Files with SharpZipLib

This article was originally posted as “C#: Extracting Zipped Files with SharpZipLib” at Programmer’s Ranch on 4th October 2014. Minor amendments have been applied in this republished version. The article illustrates how to reference and work with a third-party library. Nowadays it’s simpler to do this using NuGet.

In this article, we’re going to learn how to extract files from a .zip file using a library called SharpZipLib. Additionally, we will also learn how to work with third-party libraries. This is because SharpZipLib is not part of the .NET Framework, and is developed by an independent team.

To get started, we need to create a new Console Application in SharpDevelop (or Visual Studio, if you prefer), and also download SharpZipLib from its website. When you extract the contents of the .zip file you downloaded, you’ll find different versions of ICSharpCode.SharpZipLib.dll for different .NET versions. That’s the library that will allow us to work with .zip files, and we need the one in the net-20 folder (the SharpZipLib download page says that’s the one for .NET 4.0, which this article is based on).

Now, to use ICSharpCode.SharpZipLib.dll, we need to add a reference to it from our project. We’ve done this before in my article “C#: Unit Testing with SharpDevelop and NUnit“. You need to right click on the project and select “Add Reference”:

cssharpziplib-add-reference-1

In the window that comes up, select the tab called “.NET Assembly Browser”, since we want to reference a third party .dll file. Open the ICSharpCode.SharpZipLib.dll file, click the “OK” button in the “Add Reference” dialog, and you’re ready to use SharpZipLib.

cssharpziplib-add-reference-2

In fact, you will now see it listed among the project’s references in the Projects window (on the right in the screenshot below):

cssharpziplib-add-reference-3

Great, now how do we use it?

This is where our old friend, Intellisense, comes in. You might recall how we used it to discover things you can do with strings in one of my earliest articles, “C# Basics: Working with Strings“. This applies equally well here: as you begin to type your using statement to import the functionality you need from the library, Intellisense suggests the namespace for you:

cssharpziplib-intellisense-namespace

Now SharpZipLib has a lot of functionality that allows us to work with .zip files, .tar.gz files and more. In our case we just want to experiment with .zip files, so we’re fine with the following:

using ICSharpCode.SharpZipLib.Zip;

That thing is called a namespace: it contains a set of classes. If you type it into your Main() method and type in a dot (.) after it, you’ll get a list of classes in it:

cssharpziplib-intellisense-zip

A namespace is used to categorise a set of related classes so that they can’t be confused with other classes with the same name. Java’s Vector class (a kind of resizable array) is a typical example. If you create your own Vector class to represent a mathematical vector, then you might run into a naming conflict. However, since the Java Vector is actually in the java.util namespace, then its full name is actually java.util.Vector.

This works the same way in C#. The List class you’ve been using all along is called is actually called System.Collections.Generic.List. We usually don’t want to have to write all that, which is why we put in a using statement at the top with the namespace.

When we’re working with a new namespace, however, typing the full name and using Intellisense allows us to discover what that namespace contains, without the need to look at documentation. In the screenshot above, we can already guess that ZipFile is probably the class we need to work with .zip files.

Intellisense also helps us when working with methods, constructors and properties:

cssharpziplib-intellisense-constructor

I suppose you get the idea by now. Let’s finally actually get something working. To try this out, I’m going to create a zip file with the following structure:

+ test1.txt
+ folder
    + test2.txt
    + test3.txt

I’ve used WinRAR to create the zip file, but you can use anything you like. I named it “zipfile.zip” and put it in C:\ (you might need administrator privileges to put it there… otherwise put it wherever you like). Now, we can easily obtain a list of files and folders in the .zip file with the following code:

public static void Main(string[] args)
{
    using (ZipFile zipFile = new ZipFile(@"C:\\zipfile.zip"))
    {
        foreach (ZipEntry entry in zipFile)
        {
            Console.WriteLine(entry.Name);
        }
    }

    Console.ReadLine();
}

This gives us:

cssharpziplib-output-list

We use the using keyword to close the .zip file once we’re done – something we’ve been doing since my article “C#: Working with Streams“. You realise you need this whenever you see either a Dispose() or a Close() method in Intellisense. We are also using looping over the zipFile itself – you realise you can do a foreach when you see a GetEnumerator() method in Intellisense. Each iteration over the zipFile gives us a ZipEntry instance, which contains information about each item in the .zip file. As you can see in the output above, entries comprise not just files, but also folders.

Since we want to extract files, folders are of no interest for us. We can use the IsFile property to deal only with files:

if (entry.IsFile)
    Console.WriteLine(entry.Name);

In order to extract the files, I’m going to change the code as follows:

        public static void Main(string[] args)
        {
            using (ZipFile zipFile = new ZipFile(@"C:\\zipfile.zip"))
            {
                foreach (ZipEntry entry in zipFile)
                {
                    if (entry.IsFile)
                    {
                        Console.WriteLine("Extracting {0}", entry.Name);
                 
                        Stream stream = zipFile.GetInputStream(entry);
                        using (StreamReader reader = new StreamReader(stream))
                        {
                            String filename = entry.Name;
                            if (filename.Contains("/"))
                                filename = Path.GetFileName(filename);
                             
                            using (StreamWriter writer = File.CreateText(filename))
                            {
                                writer.Write(reader.ReadToEnd());
                            }
                        }
                    }
                }
            }
         
            Console.ReadLine();
        }

Note that I also added the following to work with File and Path:

using System.IO;

Extracting files involves a bit of work with streams. The zipFile’s GetInputStream() method gives you a stream for a particular entry (file in the .zip file), which you can then read with a StreamReader as if you’re reading a normal file.

I added a bit of code to handle cases when files are in folders in the .zip file – I am finding them by looking for the “/” directory separator in the entry name, and then extracting only the filename using Path.GetFileName(). [In practice you might have files with the same name in different folders, so you’d need to actually recreate the folders and put the files in the right folders, but I’m trying to keep things simple here.]

Finally, we read the contents of the entry using reader.ReadToEnd(), and write it to an appropriately named text file. If you run this program and go to your project’s bin\Debug folder in Windows Explorer, you should see the test1.txt, test2.txt and test3.txt files with their proper contents. [Again, the proper way to deal with streams is to read chunks into a buffer and then write the file from it, but I’m using reader.ReadToEnd() for the sake of simplicity.]

Excellent! In this article, we have learned to list and extract files from a .zip file. We also learned why namespaces are important. But most importantly, we have looked at how to reference third party .dlls and discover how to use them based only on hints from Intellisense and our own experience. In fact, the above code was written without consulting any documentation whatsoever, solely by observing the intellisense for SharpZipLib. While it is usually easier to just find an example on the internet (possibly in some documentation), you’ll find that this is a great skill to have when documentation is not readily available.

P2P Chat with Akka .NET using Akka.Remote

In this article, we’re going to develop a Peer-to-Peer (P2P) Chat application. This means that unlike the official Chat example, which has distinct Client and Server roles, each running instance of the application is exactly the same, except for configuration. The Akka.Remoting documentation explains that Akka.Remote is better suited for P2P applications rather than client/server.

In my typical style, I am keeping this example super simple so that we can focus on learning to message remote actors using Akka.Remote. I am still learning to use Akka .NET, so do not consider this article as an example of best practices.

The source code for this article is available at the Gigi Labs BitBucket repository.

NuGet Packages

Aside from the Akka package needed by all Akka .NET applications, we will also need the Akka.Remote package if we want to send messages to remote actors.

Install-Package Akka
Install-Package Akka.Remote

Configuration

If you’re going to use HOCON configuration from your App.config file, you need to declare a configSection for it:

  <configSections>
    <section name="akka" type="Akka.Configuration.Hocon.AkkaConfigurationSection, Akka" />
  </configSections>

You then set up Akka.Remote as follows:

  <akka>
    <hocon>
      <![CDATA[
        
        akka
        {
            actor
            {
                provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote"
            }

            remote 
            {
                helios.tcp
                {
                    port = 5248
                    hostname = localhost
                }
            }
        }
      
      ]]>
    </hocon>
  </akka>

The provider part is always the same, so you can just copy it. The helios.tcp section specifies the TCP endpoint on which the ActorSystem will listen for incoming connections, in this case localhost:5248.

For this particular example only, I am also going to include some AppSettings that we need in order to differentiate between different running instances of the chat application:

  <appSettings>
    <add key="actorSystemName" value="ChatPeer1" />
    <add key="remoteActorAddress" value="akka.tcp://ChatPeer2@localhost:5249/user/ChatActor" />
  </appSettings>

The actorSystemName setting has two purposes here.

  1. We will use it to display a different console title, so that we can distinguish between different running instances of the same application.
  2. We will actually give a different name to each running ActorSystem.

The remoteActorAddress setting, on the other hand, tells us the location of the remote chat actor. In this way, two running instances of the application will be able to connect and send messages to each other:

akka.remote-p2p-design

Typically you could just have one instance connect to the other, and the second communicates to the first via Sender.Tell() as in the Sending Messages to Remote Actors documentation. I arbitrarily chose not to do this to keep the application instances as symmetrical as possible (which is a typical trait of P2P applications).

Chat Application

Without further ado, here is the full code for the P2P Chat application within a console application’s Main() method:

            string actorSystemName = ConfigurationManager.AppSettings["actorSystemName"];
            Console.Title = actorSystemName;

            try
            {
                using (var actorSystem = ActorSystem.Create(actorSystemName))
                {
                    var localChatActor = actorSystem.ActorOf(Props.Create<ChatActor>(), "ChatActor");

                    string remoteActorAddress = ConfigurationManager.AppSettings["remoteActorAddress"];
                    var remoteChatActor = actorSystem.ActorSelection(remoteActorAddress);

                    if (remoteChatActor != null)
                    {
                        string line = string.Empty;
                        while (line != null)
                        {
                            line = Console.ReadLine();
                            remoteChatActor.Tell(line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("Could not get remote actor ref");
                        Console.ReadLine();
                    }
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex);
            }

From all this code, there are only two parts that are important to note. First, we are creating a local chat actor. This is what the remote actor will connect to in order to talk to the current instance of the application. It does this using the highlighted portion of code. It is simply getting a reference to the remote actor (using the address we specified in configuration) and locating it via an ActorSelection.

The ChatActor doesn’t do anything special. It simply writes whatever message it receives to the console:

    public class ChatActor : TypedActor, IHandle<string>
    {
        public ChatActor()
        {
            
        }

        public void Handle(string message)
        {
            using (var colour = new ScopedConsoleColour(ConsoleColor.White))
                Console.WriteLine(message);
        }
    }

It’s using the ScopedConsoleColour utility class from my Scope Bound Resource Management in C# article just to make received text look different from the text you type in:

    public class ScopedConsoleColour : IDisposable
    {
        private ConsoleColor oldColour;

        public ScopedConsoleColour(ConsoleColor newColour)
        {
            this.oldColour = Console.ForegroundColor;

            Console.ForegroundColor = newColour;
        }

        public void Dispose()
        {
            Console.ForegroundColor = this.oldColour;
        }
    }

Running the Application

We want to run two instances of the same application, but using different configuration. This not only allows us to recognise which is which, but also ensures that each instance can connect to the other at the right endpoint. The applications could run on the same machine or on different machines altogether.

The first instance will use configuration as shown earlier:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="akka" type="Akka.Configuration.Hocon.AkkaConfigurationSection, Akka" />
  </configSections>
    
  <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>

  <appSettings>
    <add key="actorSystemName" value="ChatPeer1" />
    <add key="remoteActorAddress" value="akka.tcp://ChatPeer2@localhost:5249/user/ChatActor" />
  </appSettings>
    
  <akka>
    <hocon>
      <![CDATA[
        
        akka
        {
            actor
            {
                provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote"
            }

            remote 
            {
                helios.tcp
                {
                    port = 5248
                    hostname = localhost
                }
            }
        }
      
      ]]>
    </hocon>
  </akka>
</configuration>

The second will use opposite configuration:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="akka" type="Akka.Configuration.Hocon.AkkaConfigurationSection, Akka" />
  </configSections>

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>

  <appSettings>
    <add key="actorSystemName" value="ChatPeer2" />
    <add key="remoteActorAddress" value="akka.tcp://ChatPeer1@localhost:5248/user/ChatActor" />
  </appSettings>

  <akka>
    <hocon>
      <![CDATA[
        
        akka
        {
            actor
            {
                provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote"
            }

            remote 
            {
                helios.tcp
                {
                    port = 5249
                    hostname = localhost
                }
            }
        }
      
      ]]>
    </hocon>
  </akka>
</configuration>

When we run the two instances, each with its own configuration, we can actually have them send messages to each other:

akka.remote-chat-demo

Disconnecting

If we close the second instance, you’ll see that this does not go unnoticed by the first instance that is still running:

akka.remote-p2p-disconnect

However, if we run the second instance again, you can see that it recovers, and from then it’s business as usual:

akka.remote-p2p-reconnect

Further Reading

This article was really just a proof of concept to show how Akka.Remote works in practice. You might also want to check out:

  1. Akka.Remote Overview (official documentation)
  2. Sending Messages to Remote Actors (official documentation)
  3. Location Transparency (official documentation)
  4. Chat Example (official examples)