OWASP Top 10 # 1 – Injection Attacks

Injection

What is it?

An injection attack is where a program, database or interpreter is tricked into executing code or performing functionality which was not intended to be run.

Though SQL injection is probably the most commonly known type of injection attack, it is a vulnerability that can affect many technologies;

  • SQL
  • XPath
  • LDAP
  • Applications / Operating Systems

SQL injection is when a query or command parameter which should contain a simple variable value actually contains additional syntax which is inadvertently executed by the database.

How does it happen?

For many web applications a URL such as http://www.TheFooSite.com/MyDatabaseTable?Id=1 would translated into a query such as:

Select * From MyDatabaseTable Where Id = 1

The integrity of the value of the id has come from the user and as such can contain potentially any malicious payload.

For example, we can change the sql query to return all data within the table:

http://www.TheFooSite.com/MyDatabaseTable?Id=1 or 1=1

Alternatively we could make the database throw an error which could potentially propagate to the user and show our technology stack, this in turn would invite any potential hacker to start a more in depth probe:

http://www.TheFooSite.com/MyDatabaseTable?Id=x

Additionally we could append on queries which query the schema tables such sysobjects and could start to expose our database structure to the user. This could then be used to append queries which exposes the potentially sensitive data contained within these tables such as credit card numbers and identity numbers:

http://www.TheFooSite.com/MyDatabaseTable?Id=SELECT name FROM master..sysobjects WHERE xtype = 'U';

Untrusted data sources

Any information which comes from the user, third party or external entity should be considered as untrusted and therefore potentially dangerous.

The sources of untrusted data are numerous:

  • From the user
    • In the URL via a query string or route parameter
    • Posted via a form
  • From the browser
    • In cookies
    • In the request headers
  • Web services calls
  • Database
  • Files such as XML, XSD, CSV

In fact anything which does not come directly from our running source code should be treated as potentially malicious. That includes data and services from within the bounds of our company as well as data entered directly from our users, even if they are our colleagues.

How can I protect myself from this?

Security is all about addressing the security concern at multiple levels; this way if one level is breached there are more levels which can catch the breach.

The principle of least privilege

The principle of least privilege is about giving any entity that requires permissions to perform a job, the minimum level of permissions it requires to perform that job.

Why grant access for the user account which is used by a web application to query an entire database, delete data, modify schema or even grant administrator level access? By granting the minimum level of permissions you dramatically reduced the level of damage that a breach can perform.

Don’t give the account db_owner access; this can read, update, delete, truncate and drop any table as well as execute any stored procedures and modify the schema.

A user account should be given access to:

  • Read from only the individual table(s) required
  • Write to only the individual table(s) required
  • Execute only the required stored procedures required

Any account accessed by a web application should probably never be given access to modify any schema, read or write to any schema or system tables and should probably not even be given access to physically delete data from any tables.

If you need to delete data, consider marking records as deleted by a status field and archiving off the records by a system task running in the background.

Where different levels of access is required between types of user account groups or roles, consider having multiple accounts. For example a public account used by public user groups and an admin account which is used by back office staff.

Please note: just because the user role is ‘admin’ it does not mean they should be given anything but the bare minimum permissions within the database.

In line SQL parametrisation

Most issues from SQL injection are from parameters being attached to the query or command via string concatenation. Take the following example which concatenates a parameter taken from the user via a URL query string parameter.

var id = Request.QueryString["Id"];
var sqlCommand = "SELECT * FROM MyTable WHERE id = " + id;

The data within the parameter is run as is within the database allowing the data within the parameter to break out of its parameter scope and into a query scope.

For example “1 or 1=1” will be searched upon as if it has two parts of the predicate.

By parametrising the query, the data contained within the parameter will stay within the scope of the parameter; here we will try and search for an id which is equal to “1 or 1=1” which at some level will either retrieve no data or throw an error when trying to convert between data types.

The following shows how we can parametrise an line query:

var id = Request.QueryString["id"];

var sqlCommand = "SELECT * FROM Foo WHERE Id = @id";

using (var connection = new SqlConnection(connString))
{
using (var command = new SqlCommand(sqlString, connection))
{
command.Parameters.Add("@d", SqlDbType.VarChar).Value = id;
command.Connection.Open();
var data = command.ExecuteReader();
}
}

We now have an error thrown within by the database as it cannot convert the string “1 or 1=1” into an integer; the data type of the id field.

Stored procedure Parametrisation

The problem with in line parametrised queries is that you have to remember to do them. By using stored procedures you are enforced to perform this step.

var id = Request.QueryString["id"];

var sqlString = "GetFoo";
using (var conn = new SqlConnection(connString))
{
using (var command = new SqlCommand(sqlString, conn))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@id", SqlDbType.VarChar).Value = id;
command.Connection.Open();
var data = command.ExecuteReader();
}
}

This will cause a similar issue that our bad string cannot be converted to an integer.

White listing untrusted data

Where possible, all untrusted data should always be validated against a white list of known safe values.

A white list states a set of rules which defines the data. Any incoming data must be validated against these rules to be considered safe. Failure of the validation should interpret the data as an expected attack.

There are multiple ways of performing white list:

  • Type conversion
    • Integer, date, GUID
  • Regular expression
    • Email address, phone number, name
  • Enumerated list of known good values
    • Titles, countries and colours for example

The following shows how we can use the try parse function to white list our id parameter by trying to convert it to an integer.

int idString;
if(!int.TryParse(idString, out id))
{
throw new Exception("The id is not a valid integer.");
}

Note: any errors should be handled, where required audited and then the user should be displayed a human readable message which gives nothing away about our implemented technology stack or in-depth details of the error.

Now that we have the parameter as integer we can add our parameter into the command as an integer:

command.Parameters.Add("@id", SqlDbType.Int).Value = id;

Any suspect attacks now should be caught way before the database which is a good place to be.

ORM’s

ORM’s should automatically parametrise any SQL.

The only thing to note is that when using ORM’s it is often required to drop to native SQL for performance reasons. When doing this care should be made to ensure all untrusted data is parametrised using the steps above.

Injection through stored procedures

Care should be taken when using stored procedures that they are not themselves concatenating parameters before calling exec.

declare @query varchar(max)
set @query = 'select * from dbo.MyTable where MyField like ''%'+ @parameter + '%''
EXEC(@query)

The stored procedure sp_executesql allows parametrising sql statements which are held as string.

declare @query varchar(max)
set @query = 'select * from dbo.Foo where MyField like ''%'+ @myFieldParameter + '%''

EXEC sp_executesql @query, N'@search varchar(50)', @myFieldParameter=@parameter

Automated SQL injection tools

There are a number of tools which can automate the hacking process, allowing people with next to no technical experience to perform automated attacks or to test the strength of web applications.

Best SQL Injection Tools

Self Closing MVC Html Helpers

The following is an example of how to write a self closing MVC Html helper similar to BeginForm(). It takes the form of a self closing DIV tag; in fact we will write a Bootstrap panel.

We will be profiting from the IDisposable and the Dispose method which will write our closing div tag

First we create a class which will be passed an Action which will write our end tag; this class implements IDisposable and calls out required action.

using System;

namespace WebApps.HtmlHelpers
{
  internal class DisposableHtmlHelper : IDisposable
  {
    private readonly Action _end;

    public DisposableHtmlHelper(Action end)
    {
      _end = end;
    }

    public void Dispose()
    {
      _end();
    }
  }
}

Now we write our help methods; a BeingPanel method which writes a div tag to the ViewContect response stream. It returns an instance of our newly created DisposableHtmlHelper as defined above. We register with it our method which will write out closing tag.

using System;
using System.Web.Mvc;

namespace WebApps.HtmlHelpers
{
  public static class HtmlHelpers
  {
    public static IDisposable BeginPanel(this HtmlHelper htmlHelper)
    {
      htmlHelper.ViewContext.Writer.Write(@"<div class="">");

      return new DisposableHtmlHelper(htmlHelper.EndPanel);
    }

    public static void EndDiv(this HtmlHelper htmlHelper)
    {
      htmlHelper.ViewContext.Writer.Write("</div>");
    }

    public static void EndPanel(this HtmlHelper htmlHelper)
    {
      htmlHelper.EndDiv();
    }
  }
}

We can now call this within a using statement in our view.

@using (Html.BeginPanel()) {
 // Monkey business would be here
}

ADO.NET – Connected Layer

Intro

The connected layer provides functionality for running SQL syntax against a connected database. The statements can be select, insert, update or delete as well as execute schema statements and the ability to run stored procedures and functions.

The connected layer requires the database connection to remain open while the database transactions are being performed.

Source Code

All source code can be found on GitHub here.

This is part of my HowTo in .NET seriies. An overview can be seen here,

Command Objects

The Command object represents a SQL statement to be run; select, insert, update, delete, execute schema, execute stored procedure etc.

The DbCommand is configured to execute an sql statement or stored procedure via the CommandText property.

The CommandType defines the type of sql statement to be executed which is stored in the CommandText property.

CommandType

Description

StoredProcedure

CommandText contains the name of a StoredProcedure or UserFunction.

TableDirect

CommandText contains a table name. All rows and columns will be returned from the table.

Text

CommandText defines an SQL statement to be executed.

The CommandType will default to Text however it is good practice to explicitly set it.

var connectionDetails =
ConfigurationManager.ConnectionStrings ["MyDatabase"];

var providerName = connectionDetails.ProviderName;
var connectionString = connectionDetails.ConnectionString;

var dbFactory = DbProviderFactories.GetFactory (providerName);

using(var cn = dbFactory.CreateConnection())
{
cn.ConnectionString = connectionString;
cn.Open();

var cmd = cn.CreateCommand();

cmd.CommandText = "Select * from MyTable";
cmd.CommandType = CommandType.Text;
cmd.Connection = cn;
}

The command should be passed the connection via the Connection property.

The command object will not touch the database until the either the ExecuteReader, ExecuteNonQuery or equivalent has been called upon.

DataReader

The DataReader class allows a readonly iterative view of the data returned from a configured command object.

A DataReader is instantiated by calling ExecuteReader upon the command object.

The DataReader exposes a forward only iterator via the Read method which returns false when the collection has been completely iterated.

The DataReader represents both the collection of records and also the individual records; access to the data is made by calling methods upon the DataReader.

DataReader implements IDisposable and should be used within a using scope.

Data can be accessed by field name and also ordinal position via the index method[] which returns the data cast into object. Alternatively methods exist to get the data for any .NET primitive type.

using (var dr = cmd.ExecuteReader ()) {
while (dr.Read ()) {
var val1 = (string)dr ["FieldName"];
var val2 = (int)dr [0];

// Get the field name or its ordinal position
var name = dr.GetName (1);
var pos = dr.GetOrdinal ("FieldName");

// Strongly Types Data
var val3 = dr.GetInt32 (1);
var val4 = dr.GetDecimal (2);
var val5 = dr.GetDouble (3);
var val6 = dr.GetString (4);

var isNull = dr.IsDBNull (5);

var fdType = dr.GetProviderSpecificFieldType (6);
}
}

The IsDBNull method can be used to determine if a value contains a null. A .NET type representation of the contained field can be retrieved with the GetProviderSpecificFieldType method.

Multiple Results

If the select statement of a command has multiple results the DataReader.NextResult() method exposes a forward only iterator through each result group:

string strSQL = "Select * From MyTable;Select * from MyOtherTable";

NextResult increments to the next result group, just like Read it returns false once the collection has been exhausted:

using (var dr = cmd.ExecuteReader ()) {
while (dr.NextResult ()) {
while (dr.Read ()) {
}
}
}

DataSet

DataReader can be used to fill a DataSet. We talk more about DataSet within the disconnected layer in the next chapter.

var dtable = new DataTable();

using(var dr = cmd.ExecuteReader())
{
dtable.Load(dr);
}

ExecuteNonQuery

ExecuteNonQuery allows execution of an insert, update or delete statement as well as executing a schema statement.

The method returns an integral representing the number of affected rows.

using (var cn = dbFactory.CreateConnection ()) {
cn.ConnectionString = connectionString;
cn.Open ();

var cmd = cn.CreateCommand ();

cmd.CommandText = @"Insert Into MyTable (FieldA) Values ('Hello’)";
cmd.CommandType = CommandType.Text;
cmd.Connection = cn;

var count = cmd.ExecuteNonQuery ();
}

Command Parameters

Command parameters allow configuring stored procedure parameters as well as parameterized sql statements which can help protect against SQL injection attacks.

It is strongly advised that any information collected from a user should be sent to the database as parameter regardless if it is to be persisted or used within a predicate.

Parameters can be added with the Command.Parameters.AddWithValue or by instantiating a DbParameter class.

The example below shows the former.

using (var cn = dbFactory.CreateConnection ()) {
cn.ConnectionString = connectionString;
cn.Open ();

var cmd = cn.CreateCommand ();

cmd.CommandText = @"Insert Into MyTable (FieldA) Values (@Hello)";
cmd.CommandType = CommandType.Text;

var param = cmd.CreateParameter ();

param.ParameterName = "@Hello";
param.DbType = DbType.String;
param.Value = "Value";
param.Direction = ParameterDirection.Input;
cmd.Parameters.Add (param);

cmd.Connection = cn;

var count = cmd.ExecuteNonQuery ();
}

The DbCommand has a DbType property which allows setting the type of the parameter, it is vendor agnostic.

SqlCommand and MySqlCommand also provide SqlDbType and MySqlDbType which can be used to set the type field from a vendor specific enum. Setting the DbType will maintain the vendor specific column and vice versa.

Executing a Stored Procedure

A stored procedure is executed by configuring a DbCommand against the name of the stored procedure along with any required parameters followed by calling ExecuteScalar or ExecuteReader.

ExecuteScalar is used to return a single value. If multiple result sets, rows and columns are returned it will return the first column from the first row in the first result set.

Parameters can either be input or output.

using(var cn = dbFactory.CreateConnection())</span></pre>
{
cn.ConnectionString = connectionString;
cn.Open();

var cmd = cn.CreateCommand();
cmd.CommandText = "spGetFoo";
cmd.Connection = cn;

cmd.CommandType = CommandType.StoredProcedure;

// Input param.
var paramOne = cmd.CreateParameter();
paramOne.ParameterName = "@inParam";
paramOne.DbType = DbType.Int32;
paramOne.Value = 1;
paramOne.Direction = ParameterDirection.Input;
cmd.Parameters.Add(paramOne);

// Output param.
var paramTwo = cmd.CreateParameter();
paramTwo.ParameterName = "@outParam";
paramTwo.DbType = DbType.String;
paramTwo.Size = 10;
paramTwo.Direction = ParameterDirection.Output;
cmd.Parameters.Add(paramTwo);

// Execute the stored proc.
var count = cmd.ExecuteScalar();

// Return output param.
var outParam = (int)cmd.Parameters["@outParam"].Value;

// This can be made on the parameter directly
var outParam2 = (int)paramTwo.Value;
}

 

Member name

Description

Input

The parameter is an input parameter (default).

InputOutput

The parameter is capable of both input and output.

Output

The parameter is an output parameter and has be suffixed with the out keyword in the parameter list of a stored procedure, built in function or user defined function.

ReturnValue

The parameter is a return value, scalar or similar but not a return set. This is determined by the return keyword in a stored procedure, built in function or user defined function.

If the stored procedure returns a set and not a single value the ExecuteReader can be used to iterate over the result:

using (var cn = dbFactory.CreateConnection ()) {
cn.ConnectionString = connectionString;
cn.Open ();

var cmd = cn.CreateCommand ();
cmd.CommandText = "spGetFoo";
cmd.Connection = cn;

cmd.CommandType = CommandType.StoredProcedure;

using (var dr = cmd.ExecuteReader ()) {
while (dr.NextResult ()) {
while (dr.Read ()) {
}
}
}
}

Database Transactions

When the writable transaction of a database involves more than one writable actions, it is essential that all the actions are wrapped up in a unit of work called a database transaction.

ACID

The desired characteristics of a transaction are defined by the term ACID:

Member name

Description

Atomicity

All changes within a unit of work complete or none complete; they are atomic.

Consistency

The state of the data is consistent and valid. If upon completing all of the changes the data is considered invalid, all the changes are undone to return the data to the original state.

Isolation

All changes within a unit of work occur in isolation from other readable and writable transactions.

No one can see any changes until all changes have been completed in full.

Durability

Once all the changes within a unit of work have completed, all the changes will be persisted.

No one can see any changes until all changes have been completed in full.
Durability
Once all the changes within a unit of work have completed, all the changes will be persisted.

Syntax

A transaction is started through the connection object and attached to any command which should be run in the same transaction.

Commit should be called upon the transaction upon a successful completion while Rollback should be called if an error occured. This can be achieved by a try catch statement:

using (var cn = dbFactory.CreateConnection ()) {
cn.ConnectionString = connectionString;
cn.Open ();

var cmdOne = cn.CreateCommand ();
cmdOne.CommandText = "spUpdateFoo";
cmdOne.Connection = cn;
cmdOne.CommandType = CommandType.StoredProcedure;

var cmdTwo = cn.CreateCommand ();
cmdTwo.CommandText = "spUpdateMoo";
cmdTwo.Connection = cn;
cmdTwo.CommandType = CommandType.StoredProcedure;

var tran = cn.BeginTransaction ();

try {

cmdOne.Transaction = tran;
cmdTwo.Transaction = tran;

cmdOne.ExecuteNonQuery ();
cmdTwo.ExecuteNonQuery ();

tran.Commit ();
} catch (Exception ex) {
tran.Rollback ();
}
}

The DbTransaction class implements IDisposable and can therefore be used within a using statement rather than a try catch. The Dispose method will be called implicitly upon leaving the scope of the using statement; this will cause any uncommitted changes to be rolled back while allowing any committed changes to remain as persisted. This is the preferred syntax for writing transactions in ADO.NET:

var connectionDetails =
ConfigurationManager.ConnectionStrings ["MyDatabase"];

var providerName = connectionDetails.ProviderName;
var connectionString = connectionDetails.ConnectionString;

var dbFactory = DbProviderFactories.GetFactory (providerName);

using (var cn = dbFactory.CreateConnection ()) {
cn.ConnectionString = connectionString;
cn.Open ();

var cmdOne = cn.CreateCommand ();
cmdOne.CommandText = "spUpdateFoo";
cmdOne.Connection = cn;
cmdOne.CommandType = CommandType.StoredProcedure;

var cmdTwo = cn.CreateCommand ();
cmdTwo.CommandText = "spUpdateMoo";
cmdTwo.Connection = cn;
cmdTwo.CommandType = CommandType.StoredProcedure;

using (var tran = cn.BeginTransaction ()) {

cmdOne.Transaction = tran;
cmdTwo.Transaction = tran;

cmdOne.ExecuteNonQuery ();
cmdTwo.ExecuteNonQuery ();

tran.Commit ();
{
}
}
}

Concurrency Issues

Writing and reading to a database does suffer from concurrency issues; multiple transactions occuring at the same time.

Concurrency Issue

Description

Lost Update

Two or more transactions perform write actions on the same record at the same time without being aware of each others change to the data. The last transaction will persist its state of the data overwriting any changes to the same fields made by the first.

Dirty Read

Data is read while a transaction has started but not finished writing. The data is considered dirty as it represents a state of the data which should not have existed.

Nonrepeatable Read

A transaction reads a record multiple times and is presented with multiple versions of the same record due to another transaction writing to the same record.

Phantom Read

Data from a table is read while inserts or deletes are being made. The result set contains missing data from the inserts which have not finished as well as records which are no longer found within table due to the deletes.

Isolation Level

Isolation levels define rules for accesing data when another transaction is running.

The level is set when creating a transaction with the BeginTransaction method and can be read with the IsolationLevel property:

using (var tran = cn.BeginTransaction(IsolationLevel.ReadCommitted)) {

cmdOne.Transaction = tran;
cmdTwo.Transaction = tran;
IsolationLevel isolationLevel = tran.IsolationLevel;

cmdOne.ExecuteNonQuery ();
cmdTwo.ExecuteNonQuery ();

tran.Commit ();
}

The IsolationLevel enum has levels considered lowest as unspecified and highest as Serializable as we traverse through the table; opposite to the amount of concucrency allowed. Chaso and snapshop are considered outside of this low to high range.

 

Isolation Level

Description (MSDN)

Unspecified

The isolation level is undetermined.

A different isolation level than the one specified is being used, but the level cannot be determined.

Often found in older technologies which work differently from current standards such as OdbcTransaction,

ReadUncommitted

A transaction reading data places no shared or exclusive locks upon the data being read.

Other transactions are free to insert, delete and edit the data being read.

This level of isolation allows a high level of concurrency between transactions which is good for performance.

This level of isolation suffers from the possibility of dirty, nonrepeatable and phantom reads.

ReadCommitted

A transaction reading data places a shared lock on the data being read.

Other transactions are free to insert or delete rows but are not given permission to edit the data being read.

This level of isolation does not suffer from dirty reads.

This level of isolation suffers from non repeatable and phantom reads.

This is the default isolation in most databases.

RepeatableRead

A transaction reading data places an exclusive lock on the data being read.

Other transactions are free to insert data into the table but are not free to edit or delete the data being read.

This level of isolation does not suffer from dirty and nonrepeatable reads.

This level of isolation suffers from phantom reads.

Serializable

A transaction reading data places an exclusive lock on the data being read.

Other transactions are not free to insert, update or delete the data being read.

This level of isolation does not suffer from dirty, nonrepeatable or phantom reads.

This level of isolation suffers from the least amount of concurrency and is bad on performance.

Chaos

Allows dirty, lost updates, phantom and nonrepeatable reads but not concurrently with other transactions with a higher isolation level than themselves.

Snapshot

Every writable transaction causes a virtual state of the data before the transaction is made. No exclusive lock is made on the data though isolation is guaranteed by allowing other  transactions to perform read actions on the data at the state before the writable transaction started,

Checkpoints

Checkpoints provide a way of defining temporary save points; data can be rolled back to these intermediatory points.

Save does not persist the changes to the database and a Commit would still be required upon completion of all writable transactions.

using (var tran = cn.BeginTransaction (IsolationLevel.ReadCommitted)) {

cmdOne.Transaction = tran;
cmdTwo.Transaction = tran;

cmdOne.ExecuteNonQuery ();

tran.Save ("Charlie");

cmdTwo.ExecuteNonQuery ();

tran.Rollback ("Charlie");
tran.Commit ();
}

Not all database vendors provide checkpoints. SQL Server does. MySQL does though the MySql Connector ADO.NET data provider does not currently appear to support this feature.

Nested Transactions

If the database vendor / ADO.NET Data Provider does not support checkpoints, nested transactions can always be implemented to achieve the same result. Here a new transaction can be created within the scope of another transaction.

using (var tranOuter = cn.BeginTransaction ()) {

cmdOne.Transaction = tranOuter;
cmdOne.ExecuteNonQuery ();

using (var tranInner = cn.BeginTransaction ()) {
cmdTwo.Transaction = tranInner;

cmdTwo.ExecuteNonQuery ();
tranInner.Rollback ();
}

tranOuter.Commit ();
}

ADO.NET – Connections And Data Providers

Intro

ADO.NET is a framework for accessing, interrogating, manipulating and persisting data in relational databases.

Source Code

All source code can be found on GitHub here.

This is part of my HowTo in .NET seriies. An overview can be seen here,

Data Providers

The framework abstracts consuming code away from the specifics of each vendor’s database implementation allowing code to be written which is virtually agnostic to the data source.

Each ADO.NET capable database provides an ADO.NET data provider which handles the databases specific implementation needs.

Through a series of classes, abstract classes and interfaces, ADO.NET provides functionality which is consistant regardless of the database vendor.

ADO.NET data providers exist for most database vendors. A list can be found here: http://msdn.microsoft.com/en-gb/data/dd363565.aspx

Configuring A Database Provider

Depending upon your choice of database and data provider, you might need to configure the provider to be used with .NET.

SQL Server is configured automatically on Windows/.NET. Under Linux/Mono SQLIte is configured automatically yet MySQL is not.

If you are using MySQL I would recommend the Connector/Net ADO.NET data provider. You can download the driver here: http://dev.mysql.com/downloads/connector/net/

The data provider is written in .NET and is provided as an assembly which needs to be installed into the GAC.

sudo gacutil -i MySql.Data.dll

To check the installation went ok. You can list the contents of the gac with the gacutil command. The command below uses the POSIX command grep to filter the results:

gacutil -l | grep My

Data providers are registered within the machine.config of the .NET version you are running.

For windows the machine.config location will look something like:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config

For Mono and Debian based Linux the machine.config location will look something like:

/usr/local/etc/mono/2.0/machine.config

The configuration will be specific to the version of your data provider. You should check the installation page of you vender to determine this. The following is for MySQL Connector provider version 6.3.5.0:

<add name=”MySQL Data Provider”
invariant=”MySql.Data.MySqlClient”
description=”.Net Framework Data Provider for MySQL”
type=”MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data,
Version=6.3.5.0, Culture=neutral,
PublicKeyToken=c5687fc88969c44d” />

This should be copied into the Machine.Config within the <DbProviderFactories> node which sits within the <System.Data> node. You should find other providers already configured.

The data provider can then be referenced as any other assembly within the GAC.

Bases Classes

ADO.NET provides a series of core and abstract classes; they provide common functionlaity that is not specific to any data priovider.

ADO.NET also provides a series of interfaces. ADO.NET providers implement these interfaces.

The data providers are welcome to inherit from the abstract classes, and most do, to reuse the common functionality associated with them.

ADO.NET API consumes the interfaces rather than the abstract classes to allow a data provider with greater control of their required funcitonality.

Below we describe the core abstract classes and their interfaces.

Class / Name Space

Description

System.Data

Provides a common namespace for most of the abstract classes and interfaces which each data provider inherit from or implement.

It also contains common entities which are not specific to a data provider; datasets, tables, rows, columns, relational constraints etc.

DbConnection

IDbConnection

Supports for configuring connections

DbTransaction

IDbTransaction

Support for database transactions

DbCommand

IDbCommand

Support for calling SQL statements, stored procedures and parameterized queries.

Provides access to the an instance of the  DataReader class through the ExecuteReader() method

DbParameterCollection

IDataParameterCollection

Provides a collection of DbParameters to IDBCommand.

DbParameter

IDbDataParameter

IDataParameter

Provides a parameter to sql statements and stored procedures. It is used by IDBCommand.

DbDataReader

IDataReader

Provides a read only iterative view of the data returned from a SQL statement.

Provides access to strongly typed data via field names or their ordinal positions.

DbDataAdapter

IDbDataAdapter

IDataAdapter

Provides access to a cached subset of data, monitoring of any changes which can then be persisted back into the database at a later time.

Below we map the abstract classes and interfaces to the SQL Server and MySQL data provider classes. As you can see the naming convention is consistent:

Class / Name Space

SQL Server

MySQL

System.Data

System.Data.SqlClient

MySql.Data.MySqlClient

DbConnection

SqlConnection

MySqlConnection

DbTransaction

SqlTransaction

MySqlTransaction

DbCommand

SqlCommand

MySqlCommand

DbParameterCollection

SqlParameterCollection

MySqlParameterCollection

DbParameter

IDbDataParameter

IDataParameter

SqlParameter

MySqlParameter

DbDataReader

IDataReader

SqlDataReader

MySqlDataReader

DbDataAdapter

IDbDataAdapter

IDataAdapter

SqlDataAdapter

MySqlDataAdapter

Though it is possible to code directly to the MySQL or SQL Server data provider classes, it is not recommended and considered bad practice.

All the examples will be make use of the DbProviderFactories class and the associated DbProviderFactory class to create instance of the required data provider specific classes. The DbProviderFactories uses late binding to to determine which class the data provider has provided as part of their implementation.

Database Connections

Connection Strings

ADO.NET allows a virtually database agnostic approach to database access within .NET.

The connection strings are vendor specific and can turn off and on a number of features each of which might be specific to each vendor.

In short the minimum requirements is the server name, the database name and some form of login criteria. As each vendors connection string is specific to the vendor and data provider. Here are some examples:

Database
Connection String
Additional
SQL Server
Data Source=localhost;Integrated Security=SSPI;Initial Catalog=MyDB

SSPI means the logged in user will be used to connect with windows integrated security.

Alternative you could provide the username and password
MySQL
Server=localhost;Database=MyDB;Uid=myUsername;Pwd=myPassword;
MySQL data adapter does not appear to support SSI

It is advised to use connection pooling when concurrent database access is required. You should check each vendor for how to set this up.

http://www.connectionstrings.com provides an excellent knowledge base for connecting to most databases in most technologies including ADO.NET.

Machine.Config

Though connection strings can be defined anywhere, it is good practice to place them within the machine.config. This can allow changing connection criteria including the database server without compiling code; great for having separate databases for development, testing and production.

Connection Strings should be placed between the appSettings and the connectionStrings node.

The connection string can be named with the name field for reference in code later.

The providers assembly is referenced with the providerName field.

SQL Server:

<connectionStrings>
<add name =”MyDatabase”
providerName=”System.Data.SqlClient”
connectionString = “Data Source=localhost; Integrated
Security=SSPI;Initial Catalog=MyDB”/>
</connectionStrings>

MySQL:

<connectionStrings>
<add name=”MyDatabase”
providerName=”MySql.Data.MySQLClient”
connectionString=”Server=localhost;Database=MyDB;User
ID=Me;Password=MyPassword” />
</connectionStrings>

ConfigurationManager

The ConfigurationManager provides access to the defined connections within the Machine.Config (and App.Config) files via the name provided. Above we defined a connection called MyDatabase:

var connectionDetails =
ConfigurationManager.ConnectionStrings["MyDatabase"];

var providerName = connectionDetails.ProviderName;
var connectionString = connectionDetails.ConnectionString;

Connecting To a Database

To connect to a database an instance of DbConnection should be initialised against the database vendor specific connection string.

The The DbProviderFactories can be used to create the database connection object. It takes the database provider name which we configured as part of the connection information.

DbProviderFactory dbFactory =
DbProviderFactories.GetFactory(providerName);

using (DbConnection connection = dbFactory.CreateConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
}

DbConnection implements IDisposable; it should be contained within a using scope.

ConnectionStringBuilder

The ConnectionStringBuilder class can be used in conjunction with a connection string to help customise a connection string in code. The index method [] can be used to set key value pairs representing connection properties.

It can be initialised with a connection string:

var connectionDetails =
ConfigurationManager.ConnectionStrings ["MyDatabase"];

var providerName = connectionDetails.ProviderName;
var connectionString = connectionDetails.ConnectionString;

var dbFactory = DbProviderFactories.GetFactory (providerName);

var builder = dbFactory.CreateConnectionStringBuilder ();
builder.ConnectionString = connectionString;
builder ["ConnectionTimeout"] = 60;

using (var connection = dbFactory.CreateConnection ()) {
connection.ConnectionString = builder.ConnectionString;
connection.Open ();
}

Connected vs Disconnected Layers

ADO.NET provides two conceptual layers; connected and disconnected.

The connected layer requires a live connection to the database to remain open during interaction. It is used for short transactions to the database such as calling stored procedures, running schema update or writeable transactions. The layer can be used for reading data though as the connection remains open; it is advised to limit the usage for short use.

The disconnected layer allows populating a DataSet object which allows an offline representation of the data. The connection remains open only for the amount of time it takes to populate the required data into the DataSet. The dataset can then be manipulated independently without the connection being open. The data can even be persisted back to the database at a later date.

Multithreading

Source Code

All source code can be found on GitHub here.

This is part of my HowTo in .NET seriies. An overview can be seen here,


Intro

Multithreading is the concept of creating and utilising multiple threads. There are a number of reasons for this:

* Split processor heavy work between all available processors to increase performance
* Prevent synchronous method calls from blocking the current thread:
* Web services
* Database Calls
* Prevent calls from the UI appearing unresponsive

ThreadStart & ParameterizedThreadStart

ThreadStart and the ParameterizedThreadStart class provide functionality for executing code within a new thread, with or without parameters.

ThreadStart

ThreadStart allows spawning code in a new thread for a parameterless delegate which returns void. Execution only starts once Start has been called upon the thread.

var aThread = new Thread(new ThreadStart(MyMethod))
{
    Name = "My Thread",     
    Priority = ThreadPriority.Highest
};      
    
aThread.Start();   

ParameterizedThreadStart

ParameterizedThreadStart allows spawning code in a new thread for a delegate which takes one parameter of type object and returns void. The object parameter is passed into the start method.

Where multiple parameters are required, these should be wrapped up in a class and passed in.

var aThread = new Thread (new ParameterizedThreadStart (MyMethod)) {
    Name = "My Thread",     
    Priority = ThreadPriority.Highest
};      

aThread.Start (new object());

Cancelling

A CancellationTokenSource instance can be used to cancel a thread.

CancellationTokenSource can be passed in directly, via a member variable of a user defined params object or simply made accessible to all required threads.

Cancel() is called upon the token if the thread should be cancelled.

var cts = new CancellationTokenSource ();

var aThread = new Thread (new ParameterizedThreadStart (MyMethod)) {
    Name = "My Thread",     
    Priority = ThreadPriority.Highest
};      

aThread.Start (cts.Token);

Thread.Sleep (10000);

cts.Cancel ();

The executing thread should monitor IsCancellationRequested or alternatively call ThrowIfCancellationRequested. ThrowIfCancellationRequested is semantically equal to throwing an OperationCanceledException when IsCancellationRequested returns true;

private void MyMethod (object obj)
{
    CancellationToken token = (CancellationToken)obj;


    for (int i = 0; i < Int32.MaxValue; i++) {    
        // Causes an exception to be raised if cancellation is called
        token.ThrowIfCancellationRequested ();


        // Alternatively check the token manually if cancellation has been raised
        if (token.IsCancellationRequested) {
            throw new OperationCanceledException (token);                
        }
    }
}

Timer Class

System.Threading.Timer allows periodic event signalling via the TimerCallback delegate.

The TimerCallback delegate returns void and takes a single parameter of type object.

A Timer is invoked with the delegate, the param object, the time in milliseconds before starting, and the time in milliseconds between events.

The following calls the method MyMethod with a params object after 2 seconds and every second afterwards:

var t = new Timer(
new TimerCallback(MyMethod), new object() , 2000, 1000); 

CLR ThreadPool

Threads are an expensive resource to spawn and terminate, as such the CLR maintains a pool of worker threads you can use.

All threads in the ThreadPool are background threads with a normal priority.

You can request work from a pool thread with the WaitCallback delegate. It takes one parameter of type object and returns void:

var wcb = new WaitCallback(DoMethod);    

The delegate is assigned via the ThreadPool class:

ThreadPool.QueueUserWorkItem(wcb, new object()); 

ThreadPool can help to ensure that the number of concurrent running threads is kept within a required tolerance, this can ensure that a server does not buckle over from trying to do too many things at one time.

Due to the nature of ThreadPool and the limited number of threads contained within, you can not guarantee the length of time before your process begins.

CancellationTokenSource can be used to cancel an executing thread on the ThreadPool.

CancellationTokenSource cts = new CancellationTokenSource ();
ThreadPool.QueueUserWorkItem (new WaitCallback (DoMethod), cts.Token);
cts.Cancel ();

static void DoMethod (object obj)
{
    CancellationToken token = (CancellationToken)obj;


    for (int i = 0; i < Int32.MaxValue; i++) {    
        token.ThrowIfCancellationRequested ();            
    }
}

Task Parallel Library

Microsoft introduced the Task Parallel Library (TPL) in .NET 4.0.

The library automatically splits up an applications workload across all available CPUs dynamically by requesting worker threads within the CLR thread pool. It provides the classes Parallel and Task.

Parallel

System.Threading.Tasks.Parallel can be used to perform an operation upon all elements in a collection or a custom counter.

The operations can take any of the System.Func or System.Action delegates.

Parallel does not guarantee the order of execution and as such should not be used when the order of execution matters.

Parallel should not be used upon small sets of data or when threads requires resources which require synchronization as this can actually decrease performance.

ForEach

To perform a delegate for each element in a collection:

Parallel.ForEach (new List<int>(), anElement => { 
    /*Some Process */ 
});

For

To perform a countered loop, where the iteration count i is available inside the iteration:

Parallel.For (0, Int32.MaxValue, i => { 
    /* Some Process */ 
});

Break and Stop

ParallelLoopState exposes Stop() and Break(). Break() will cause all iterations with an index less than the callers to finish before the loop is terminated. Stop will simply stop as soon as it is conveniently possible.

Parallel.For (0, Int32.MaxValue, (i, loopState) => { 
    loopState.Stop();
    loopState.Break();
    /*Some Process */ 
});

Invoke

Allows executing a series of operations, the CLR will attempt to do them in parallel.

If the operations modify a shared resource the operation will automatically not be executed in parallel.

Parallel.Invoke( 
    () => { /* Do something #1 */ }, 
    () => { /* Do something #2 */ }, 
    () => { /* Do something #3 */ }, 
    () => { /* o something #4  */ });

Task Class

A simple alternative to asynchronous delegates:

Task.Factory.StartNew (() => {
    DoSomething ();
});  

A task scheduler is responsible for starting and managing tasks. It will by default use threads from the ThreadPool.

The task can be created and started in separate steps:

var aTask = new Task (() => {
    DoSomething ();
});

aTask.Start ();

The wait function can be called to pause the current thread until the task has finished:

aTask.Wait ();

Alternatively the task can be run synchronously:

aTask.RunSynchronously ();

Results can be returned with the Result property. This will block the current thread until the thread has finished executing. Result can only be called on Task:

var aTask = new Task<bool> (() => {
    return true;
});

var result = aTask.Result;

Continuation Task

The ContinueWith method can be used to execute another process as soon as a Task finishes.

Task<bool> t = Task.Run (() => {
    return true;
}).ContinueWith ((x) => {
    return !x.Result;
}); 

var result = t.Result;

ContinueWith can also take a TaskContinuationOptions enum to denote when the method should run; OnlyOnRanToCompletion,OnlyOnFaulted and OnlyOnCanceled

Task<string> t = Task.Run (() => {
    return string.Empty;
}); 

t.ContinueWith ((i) => {
    return "OnlyOnCanceled";
}, TaskContinuationOptions.OnlyOnCanceled); 

t.ContinueWith ((i) => {
    return "OnlyOnFaulted";
}, TaskContinuationOptions.OnlyOnFaulted); 

t = t.ContinueWith ((i) => {
    return "OnlyOnRanToCompletion";
}, TaskContinuationOptions.OnlyOnRanToCompletion); 

var result = t.Result;

Child Tasks

Child tasks can also be assigned when running a Task. Here the parent task will not be deemed as finished until all child tasks have finished. Child Tasks are added with TaskCreationOptions.AttachedToParent.

  Task<int[]> parent = Task.Run (() => {
    var results = new int[2]; 
    new Task (() => results [0] = 0,                     
        TaskCreationOptions.AttachedToParent).Start ();                 
    new Task (() => results [1] = 1, 
        TaskCreationOptions.AttachedToParent).Start ();                       
    return results;
});             

var finalTask = parent.ContinueWith (
                 parentTask => {


        var count = 0;
        foreach (int i in parentTask.Result) {
            count += i;
        }
        return count;              
    });  

finalTask.Wait ();       
var finalResult = finalTask.Result;    

TaskFactory

A TaskFactory can be used to define settings for child tasks:

Task<int[]> parent = Task.Run (() => {

    var results = new int[2];                   


    TaskFactory tf = new TaskFactory (
                         TaskCreationOptions.AttachedToParent,                    
                         TaskContinuationOptions.ExecuteSynchronously);                 

    tf.StartNew (() => 0);                 
    tf.StartNew (() => 1);                 

    return results;
});               

var finalTask = parent.ContinueWith (
                    parentTask => { 
        var count = 0;
        foreach (int i in parentTask.Result) {
            count += i;
        }

        return count;                
    });

finalTask.Wait ();
var finalResult = finalTask.Result;    

WaitAll

WaitAll can be used to wait for all child tasks to finish executing:

var tasks = new Task[3];            
tasks [0] = Task.Run (() => {
    return 1;
});             

tasks [1] = Task.Run (() => { 
    return 2;
}); 

tasks [2] = Task.Run (() => {
    return 3;
}
);

Task.WaitAll (tasks);  

WaitAny

WaitAny causes the current thread to block until any task has completed processing.

Task<int>[] tasks = new Task<int>[3];

tasks [0] = Task.Run (() => {
    return 1;
});

tasks [1] = Task.Run (() => {
    return 2;
});

tasks [2] = Task.Run (() => {
    return 3;
});

int result = 0;

while (result < 6) { 
    int i = Task.WaitAny (tasks);
    var completedTask = tasks [i];                 

    result += completedTask.Result;

    var taskList = tasks.ToList ();
    taskList.RemoveAt (i);

    tasks = taskList.ToArray ();
}

WhenAll

WhenAll can be used to schedule a continuation task to run after all child tasks have finished executing:

var tasks = new Task<int>[3];

tasks [0] = Task.Run (() => {
    return 1;
});

tasks [1] = Task.Run (() => {
    return 2;
});

tasks [2] = Task.Run (() => {
    return 3;
});

int result = 0;
var completionTask = Task.WhenAll (tasks);

completionTask.ContinueWith (x => result += x.Result.Sum( y => y));    

Timing Out A Task

An overload of the WaitAny method takes a maximum wait time. This can be used to cancel a task after a set time period.

var longRunning = Task.Run (() => {
    Thread.Sleep (10000);
    return 1;
}); 

int index = Task.WaitAny (new[] { longRunning }, 1000); 

var result = 0;

if( longRunning.IsCompleted)
    result += longRunning.Result;

Canceling Tasks

Tasks can be called with a CancellationTokenSource.

When cancelling a task with a CancellationTokenSource it will appear to end as if no error has happened. If you require the task to error out upon cancellation then you should throw a OperationCanceledException. An alternative to catching the exception is to use a continuation task with the TaskContinuationOptions.OnlyOnCanceled option.

var cts = new CancellationTokenSource ();
var token = cts.Token;
var isCancelled = false;

Task<bool> task = Task.Run (() => {
    while (!token.IsCancellationRequested) {  
        Thread.Sleep (1000);
    }                       
    throw new OperationCanceledException ();
}, token).ContinueWith ((t) => { 
    return true;
}, TaskContinuationOptions.OnlyOnCanceled);

Thread.Sleep (3000);     

cts.Cancel ();

var result = task.Result;    

Async Keyword

.NET 4.5 now supports the Async keyword, the CLR can call any method asynchronously virtually automatically.

Methods requiring asynchronous calling are marked as async and return either Task or Task depending upon if they return type T or void.

In the following example we have two methods which are tagged as async. They each call a method which returns a Task or Task param.

public async Task<bool> RunWithReturn ()
{
    return await TaskWithReturn ();
}

public async Task RunNoReturn ()
{
    await TaskNoReturn ();
}

private Task<bool>  TaskWithReturn ()
{
    var t = new Task<bool> (() => {
        Thread.Sleep (1);
        return true;
    });

    t.Start ();
    return t;
}

private Task TaskNoReturn ()
{
    var t = new Task (() => {
        Thread.Sleep (1);
        IsSet = true;
    });

    t.Start ();
    return t;
}

These methods returning Task and Task are called as normal. They could be called like:

Task<bool> t1 = TaskWithReturn ();
Task t2 = TaskNoReturn ();

The method is not actually executed until the returned task is called with the await keyword:

var result = await t1;
await t2;

The method call and the await can be wrapped up in one line:

await TaskWithReturn ();
await TaskNoReturn ();

Asynchronous Delegates

Delegates allow asynchronous invocation by BeginInvoke() and EndInvoke()

BeginInvoke() and EndInvoke() are automatically generated by the compiler and have API based upon the parameters and return type of the delegate they were defined against.

BeginInvoke method:

* Takes the the parameters the delegate was defined against
* Takes an optional callback method
* Takes an optional state parameter of type object. This can be cast into any type inside the callback method.
* Returns an IAsyncResult which can help with getting the results back and also with working with the callback

EndInvoke method:

* Returns the same type the delegate was defined against
* Blocks the thread until the the delegate has finished executing

IAsyncResult provides various ways of waiting for the results:

* IsCompleted
* AsyncState
* AsyncWaitHandle
* CompletedSynchronously

IsCompleted

?

Returns true when the delegate has finished running:

delegate  bool AnAction(bool paramA, int param2 );

var d = new AnAction(ActionMethod);   

IAsyncResult ar = d.BeginInvoke(true, 1, null, null);   

do
{  
Thread.Sleep(10000);
 } while(!ar.IsCompleted);   

var result = d.EndInvoke(ar);

AsyncWaitHandle

Wraps up the IsComplete and Sleep from above into one handy function:

var d = new AnAction (DoAction);  
IAsyncResult ar = d.BeginInvoke (true, 1, null, null);   

do {
} while (!ar.AsyncWaitHandle.WaitOne (1000, true));

var result = d.EndInvoke (ar);

AsyncCallback With State

Triggers a callback delegate upon completion.

The callback will be on the same thread as the delegate and not on the main thread.

Here we create a new Foo object which will have all the parameters of the callback wrapped up into one class.

var d = new AnAction(DoAction);  

var ar = d.BeginInvoke(true, 10, 
    new AsyncCallback(MyCallback), 
    new object());

public void MyCallback(IAsyncResult iar) 
{   
    AsyncResult ar = (AsyncResult)iar;   
    var d = (AnAction)ar.AsyncDelegate;
    var result = d.EndInvoke(ar);
    var obj = (object)ar.AsyncState;
} 

Cancelling An Asynchronous Delegate

Cancellation of an executing asynchronous delegate can be performed with the CancellationTokenSource ( See cancelling Tasks).

Parallel LINQ Queries (PLINQ)

PLINQ libraries allow an easy API for running queries in a parallel manner.

PLINQ is requested in code though the CLR will decide if parallel execution will beneficial or not.

System.Linq.ParallelEnumerable contains all the extension methods for PLINQ.

Spawning

Requesting parallel execution is as simple as calling the Parallel method.

Extension methods:

var data = myData.AsParallel().Select( x => x );

Natural methods:

var data = ( from value in myData.AsParallel() select value );

WithDegreeOfParallelism

PLINQ will normally use all available processors to process a query though never more than 64. WithDegreeOfParallelism can be used to restrict the number processors that it it will consume.

var data = 
myData.AsParallel ().WithDegreeOfParallelism(2).Select (x => x);

AsOrdered

PLINQ does not guarantee the order of processing the iterations.

AsOrdered can be called to instruct PLINQ to preserve the ordering within the result set. The query will still be run in parallel.

var data = myData.AsParallel ().Select (x => x).AsOrdered();

AsSequential

AsSequential can be used to force parts of a Linq query to be executed sequentially and not in parallel. Other parts of the query will still be performed in parallel.

var data = myData.AsParallel ().Select (x => x).AsSequential();

ForAll

ForAll allows parallel iteration through a collection. Order is not guaranteed; it will remove any sort order upon a collection and will iterate through each member when the item is available.

var myData = new List<int> () { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

var ints = new List<int> ();

myData.AsParallel ().ForAll (x => ints.Add (x));

Errors

PLINQ will throw an AggregateException when any errors occur within the query when processing. All iterations will be performed; not matter how many errors occur.

Cancelling

The CancellationTokenSource can be used to cancell an executing PLINQ query. This is passed in with the WithCancellation method:

var cs = new CancellationTokenSource ();

Extension methods:

var myData = new List<int> () { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var data = myData.AsParallel ().
          Select (x => x).WithCancellation (cs.Token);

Natural Linq:

var myData = new List<int> () { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var data =
    (from Value in myData.AsParallel ().WithCancellation (cs.Token)
     select Value);

On the original thread you can call Cancel upon the token:

cs.Cancel ();

WithExecutionMode

WithExecutionMode can be used for force PLINQ into a parallel query though this should be used with care.

myData.AsParallel ().Select (x => x).
WithExecutionMode (ParallelExecutionMode.ForceParallelism);

File IO

In high latency environments, asynchronous file IO can provide performance gains by releasing threads until the file system responds:

public async Task CreateAndWriteAsyncToFile (byte[] data, string aFileName)
{
    using (FileStream stream = new FileStream (aFileName, 
                                   FileMode.OpenOrCreate,         
                                   FileAccess.Write, 
                                   FileShare.Read, 1024 * 4, true)) {         
        await stream.WriteAsync (data, 0, data.Length);     
    }
}

public async Task<byte[]> ReadFileAsync (string aFileName, int length)
{
    byte[] data = new byte[length];


    using (FileStream stream = new FileStream (aFileName, 
                                   FileMode.Open,         
                                   FileAccess.Read, 
                                   FileShare.Read, 1024 * 4, true)) {         
        await stream.ReadAsync (data, 0, data.Length);     
    }

    return data;
}

Networking

Asynchronous network downloads can be achieved with the GetStringAsync method.

The GetStringAsync uses asynchronous code internally and returns a Task to the caller that will finish when the data is retrieved:

Seeing as GetStringAsync returns a Task instance WhenAll can be used to register a callback when multiple instances are returned:

public async Task<string> ReadAsyncHttpRequest ()
{     
    HttpClient client = new HttpClient ();     
    return await client.GetStringAsync ("http://www.google.com");
}

HttpClient can be found within the System.Net.Http namespace which is found within the assembly System.Net.Http.dll.

public async Task<string> ExecuteMultipleRequestsInParallel ()
{     
    HttpClient client = new HttpClient ();     

    Task<string> one = client.GetStringAsync ("http://www.google.co.uk/");     
    Task<string> two = client.GetStringAsync ("http://monodevelop.com/");     

    await Task.WhenAll (one, two); 

    return one.Result + two.Result;
}