Wednesday, 14 December 2011

MySQL - Data Binding

Our first example was very little ASP.NET'ish. With ASP.NET, databinding is the big thing, and once you've used it for a while, you will likely understand why. Databinding can really save some time for you. We will start off with a very basic example of databinding, but even though it's simple, it's also extremely useful. Populating a dropdown list can be a boring job, but have a look how easy it can be done. Start off by adding a dropdown list to the page:
<asp:DropDownList runat="server" id="ddlUsers" datavaluefield="id" datatextfield="name" />
The datavaluefield property tells the control which database field should be used for the value property of each item, and the datatextfield tells the control which field to use for the actual text of the item. That's all we need in the markup department, so switch to CodeBehind. Here we will use almost the same code as in the last chapter, with a small modification:
try
{
    using(OdbcConnection connection = new OdbcConnection(ConfigurationManager.ConnectionStrings["MySQLConnStr"].ConnectionString))
    {
        connection.Open();
        using(OdbcCommand command = new OdbcCommand("SELECT id, name FROM test_users", connection))
        using(OdbcDataReader dr = command.ExecuteReader())
        {
            ddlUsers.DataSource = dr;
            ddlUsers.DataBind();
            dr.Close();
            
        }
        connection.Close();
    }
}
catch(Exception ex)
{
    Response.Write("An error occured: " + ex.Message);
}
Only 2 things have changed from the last example: We've added a field to the query (the id field), and we have changed the loop to a couple of databinding lines. The first one assigns the datasource of the dropdown list to our datareader, and the second one tells the dropdown list to perform the databinding. That's all we need, which you will see if you run the website. The dropdown list will be filled with names from our test table.

This is just a basic example. Later on, when we work with repeaters, datagrids etc. you will surely realize the true potential of databinding.

MySQL - First access

Okay, let's try accessing our test table for the first time, using ASP.NET. First of all, we need to import the System.Data.Odbc namespace. Add the following line in the top of your CodeBehind file:
using System.Data.Odbc;
This will give us access to a bunch of ODBC related classes. For now, we will need 3 of them:

OdbcConnection - Provides an ODBC connection to a database.
OdbcCommand - Will execute an SQL command using an existing OdbcConnection.
OdbcDataReader - Will provide fast access to the data which the OdbcCommand will bring us.


The first example will focus on getting access to our test data, and simply printing it out, and while this is not how we normally do things with ASP.NET, it's simply meant to show you the most basic example of data access. Since we write directly to the (top of the) page, we don't need to add any markup code. Simply go to the CodeBehind (.cs) file, and add the following code to the Page_Load method:
try
{
    using(OdbcConnection connection = new OdbcConnection(ConfigurationManager.ConnectionStrings["MySQLConnStr"].ConnectionString))
    {
        connection.Open();
        using(OdbcCommand command = new OdbcCommand("SELECT name FROM test_users", connection))
        using(OdbcDataReader dr = command.ExecuteReader())
        {
            while(dr.Read())
                Response.Write(dr["name"].ToString() + "<br />");
            dr.Close();
        }
        connection.Close();
    }
}
catch(Exception ex)
{
    Response.Write("An error occured: " + ex.Message);
}
Okay, if you come from the PHP world, you're probably about to run away because of the big amount of code needed to perform a simple database extraction. However, C# is an Object Oriented language, and sometimes it just takes a bit more code to make a more elegant solution. Of course, code like this can be gathered in reusable classes and methods, but for now, we do it the basic way.

Now, let me try to explain the various lines of code. First we create an OdbcConnection object, to establish the connection with the database. We use the ConfigurationManager class to obtain the connection string which we stored in the web.config file in the previous chapter. It's with in a using() construct, which is a convenint way to tell C# that when the block of code ends, it should dispose the object. If we didn't use it, we would instead have to call connection.Dispose(); when we were done. Next, we open the connection, and then we create an instance of the OdbcCommand class, which is used to fire off SQL queries against the database. Using the command object, we query the database, and in return we get an OdbcDataReader. The DataReader class is the simplest and fastest way to access a database in .NET.

We loop through the datareader, and on each iteration, we output the name field from the database, along with a linebreak tag. Pretty simple, right? As you can see, the entire data access block is encapsulated in a try..catch block. Lots of things can go wrong when interacting with a database, so using a try..catch block is recommended. Using dr["name"], we get the result as an object, which is why I'm calling the ToString(). If you wish for more control of the datatype you receive from the reader, you can use the Get* methods, like GetInt32(), GetString() etc. However, these methods require you to use the index of the field in your query, and not the name of the field, which is not as convenient.

Run the website, and have a look at the output. It should contain a bunch of names from our test table, or which ever table you're using.

MySQL - Getting started

The easiest way to use MySQL with ASP.NET is to use the MySQL ODBC Connector from MySQL AB. If you're work is being hosted by a company which supports MySQL, they have probably already installed this, but if you're testing your code on your own machine with your own instance of MySQL, then you need to install this. MySQL Connector/ODBC 3.51 can be downloaded from this page: http://dev.mysql.com/downloads/connector/odbc/3.51.html

Once installed, you will be able to connect to your MySQL database server. Doing so is quite easy, but we will also need some data to test on. During the next chapters, we will be using a table called test_users. You can find the SQL code to create and fill the table with test data below. Run it trough your favorite MySQL client's SQL function, or use the command prompt to import into a new or existing database.

First of all, let's create a new project for this in Visual Web Developer. Secondly, let's store the connection information for the database in once place, so we can reuse all over our application. We will do this with the web.config file. You can add it by right clicking the project name in the Solution Explorer, and selecting "Add New Item". From the dialog that pops up, select "Web Configuration File". Press Add, and the file will be added to your project. It will automatically be opened. Now, find the part that says and replace it with this:

<connectionStrings>
  <add name="MySQLConnStr" connectionString="DRIVER={MySQL ODBC 3.51 Driver};Database=YourDatabase;Server=localhost;UID=YourUsername;PWD=YourPassword;"/>
</connectionStrings>
By doing so, we can access the connection string from all over the application. You should replace 3 values in it: YourDatabase, YourUsername and YourPassword. They should of course be replaced with the name of the database that you care to use, as well as the username and password for one of the users of the MySQL database server. In the next chapter, I will show you how we retrieve the value and use it.

Here is the SQL code to create and fill our test table with some data:
CREATE TABLE `test_users` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(100) NOT NULL default '',
  `country` varchar(100) NOT NULL default '',
  PRIMARY KEY  (`id`)
); 

INSERT INTO `test_users` VALUES (1,'John','USA');
INSERT INTO `test_users` VALUES (2,'Mark','Canada');
INSERT INTO `test_users` VALUES (3,'Lukas','Germany');
INSERT INTO `test_users` VALUES (4,'Ingrid','Sweden');

MySQL - Introduction

MySQL is one of the most used database servers on the Internet. Part of its popularity comes from the tight integration with PHP, but ASP.NET can use it as well. By using the Odbc classes from the .NET framework, you can easily work with a MySQL database.

This tutorial will not cover installing MySQL, nor will it cover SQL in general. It will focus on using MySQL with ASP.NET.

Follow the next chapters to get started with using MySQL together with ASP.NET. We will cover topics from the first connection to databinding and much more.

Changing the active culture

In a previous chapter, we had a look at the CultureInfo class, and we briefly discussed how to change it for a page. However, since changing the current culture is so essential, this chapter will contain an in-depth look of the different ways to accomplish this.

Automatic

Both Culture and UICulture is automatically set based on the browser settings of your visitor. Try running the following page:
<%@ Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>CultureInfo demo</title>
</head>
<body>
    <form id="MainForm" runat="server">
        <% Response.Write("Your current culture: " + System.Globalization.CultureInfo.CurrentCulture.DisplayName); %>
    </form>
</body>
</html>
Now, access your browsers language settings:

Internet Explorer: Click the Tools button, select Internet Options, then click the Languages button.

Firefox: Click the Tools menu, select Options, select the Content tab and then click the Choose button in the Languages group.

Add another language, and then move it to the top of the list. Close the dialog and reload the page (F5). You will now see the name of the culture matching your newly selected language.

The Page directive/class

As we saw in the previous chapter, we can simply define both Culture and UICulture by accessing the properties in the Page directive:

<%@ Page Language="C#" Culture="en-US" UICulture="en-US" %>


Since the Page directive is just a shortcut to the Page class, this can be done from CodeBehind as well. However, we have to do it at a certain point, before the page is being rendered, to make sure that it has the desired effect. This is where the InitializeCulture() method comes into play, a method that is called by ASP.NET pretty early in the Page life cycle, which you can override:
public partial class CultureInfoTest : System.Web.UI.Page
{
    protected override void InitializeCulture()
    {
        Page.Culture = "en-GB";
        Page.UICulture = "en-GB";
    }

    protected void Page_Load(object sender, EventArgs e)
    {        
        Response.Write(Page.Culture);
    }
}
You should be aware that the Page.Culture and Page.UICulture properties them self are merely shortcuts to the System.Threading.Thread.CurrentThread.CurrentCulture and System.Threading.Thread.CurrentThread.CurrentUICulture.

Globally

You can set the Culture and UICulture for all your pages, via the web.config file. Use the globalization node, which is a child node of the system.web node, like this:

<globalization uiCulture="en-US" culture="en-US" />

Localizing the CodeBehind

In the previous chapters, we only used localization for the markup part of the webpage, but localizing your strings in Code Behind is just as simple. Here are the techniques for doing this, with some sample code to get you started.

Direct access

Since the .NET framework takes your global resource files and turns them into strongly typed classes, you can actually reference them as such. For instance, if you have a global resource file called MyGlobalResources.resx, with a resource row with a name of HelloWorldString, you can access it like this:
lblHelloWorld.Text = Resources.MyGlobalResources.HelloWorldString;

GetLocalResourceObject()

With a call to GetLocalResourceObject(), you can get a specific row from your local resource file. It is returned as an object, but you can always call the ToString() method on it. For this to work, you have to be within a file that has a local resource file. To get a row from it, simply specify the name of the row as a parameter to the method, like this:
lblHelloWorld.Text = GetLocalResourceObject("lblHelloWorld.Text").ToString();

GetGlobalResourceObject()

The GetGlobalResourceObject() method works pretty much like the local version described above, but for global resources instead. You have to specify an extra parameter though, to tell ASP.NET in which global resource file you want to look for the row in, so the first parameter is the name of the resource class generated from the resource file, while the secondary parameter is for specifying the name of the row you're looking for, like this:
lblHelloWorld.Text = GetGlobalResourceObject("MyGlobalResources", "HelloWorldString").ToString();
Which approach to use mostly depends on the situation and what you prefer, but the first one does have a big advantage: Since it's strongly typed, the compiler will alert you if the row you are trying to retrieve no longer exists, allowing you to catch any problems before they go into production.

Implicit & Explicit localization

Implicit localization

Implicit localization is used within your markup, and its main advantage is that it allows you to localize several properties of the same control/object, without explicitly referencing each property. In our Localized Hello World chapter, we used it, and saw how we could set the meta:resourcekey property of a control, and then automatically have its Text property mapped to the resource row in our resource file. Let's expand a bit on that example, to have several properties localized. If you haven't already done so, you should read the Localized Hello World chapter now and create the project from it, as the following example uses it:

<asp:Label runat="server" ID="lblHelloWorld" Text="Hello, world!" Font-Names="Verdana" ForeColor="Blue" meta:resourcekey="lblHelloWorld" />

In the three resource files we created (default, Germand and Spanish), you can now add two extra rows to each of them, with the names "lblHelloWorld.ForeColor" and "lblHelloWorld.Font-Names", and then define different values for it. For instance, the default label color could be blue, the German version could be green and the Spanish version could be red, and you could define different font names for each of them as well. This makes it really easy to localize e.g. controls, because we only have to define the name of the resource row - each property is automatically mapped.

Explicit localization

With explicit localization, you pick out a specific resource row from your resource file, which is returned to you, and while implicit localization can be helpful when localizing webcontrols and other declarative objects, explicit localization is the only possible way of doing things in any other circumstance. Let's see how the above example would look with explicit localization:

<asp:Label runat="server" ID="lblHelloWorld2" Text="<%$ Resources:lblHelloWorld.Text %>" Font-Names="<%$ Resources:lblHelloWorld.Font-Names %>" ForeColor="<%$ Resources:lblHelloWorld.ForeColor %>" />

We simply re-use the resource rows from our previous example, and as you can see, the markup for explicit localization is a bit more complicated and verbose than for implicit localization. The syntax for retrieving a resource row is like this:

<%$ Resources:[resource class name,]RowName %>

As you can see, we didn't specify a resource class name in our example, because we use a local resource. If you use a global resource, you should specify the name of the class it results it, which as a rule of thumb is the same as the filename, but without the .resx extension. So for instance, if you have a global resource file with the name of MyGlobalResources.resx, you would obtain a resource from it like this:

<%$ Resources: MyGlobalResources,NameOfRow %>

As simple as that.

Local & Global resources

When localizing your ASP.NET websites, you can store your resources as either a local or a global resource. A local resource is specific to a certain page, which is the only one who can access it, while global resources can be accessed from anywhere.

Local resources are kept in the special App_LocalResources folder, while global resources are kept in the App_GlobalResources folder. Local and global resource files will look exactly the same, so the only apparent difference, is the folder they're placed in. However, they are used differently. For instance, with local resources, you need a resource file for each of your pages, and an extra one of each of the desired languages. So if you have a website with 10 pages, each localized into two other languages, besides the default language, it will amount to 30 resource files. With global resources, you would only need (but not be limited to) one file per language, no matter how many pages you have. On the other hand, each of these files could get pretty hard to manage, if your site has lots of localized content.

You will likely always need some global resources, but if you prefer, you may skip the local resources and only use global ones. It's really up to you.

The CultureInfo class

When it comes to localization of your application, especially one class is of great importance: The CultureInfo class from the System.Globalization namespace. From this class, you can get information about pretty much every possible culture out there, including a wide range of culture specific settings. The CultureInfo class can really help you when localizing your webpages, most notably because ASP.NET will keep a reference to the specific CultureInfo instance related to a specific visitor. Does it sound complicated? Let me show you a little example:
<%@ Page Language="C#" Culture="Auto" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>CultureInfo demo</title>
</head>
<body>
    <form id="MainForm" runat="server">
        <% Response.Write("Your current culture: " + System.Globalization.CultureInfo.CurrentCulture.DisplayName);    %>
    </form>
</body>
</html>
Try running this and you will get a culture related to you - but how? Actually, since the Culture property of the Page directive is set to Auto, this is controlled by your browser. Most browsers allow you to set your favorite languages, and from that, ASP.NET tries to detect which culture to use for you. We will look into that in greater detail later on. Your current culture is used in lots of cases, for instance when formatting dates and numbers, since that varies from culture to culture. Now, you may want to use a specific culture, no matter what your visitors browser tells you. In that case, you can set the Culture property of the page, like this:

<%@ Page Language="C#" Culture="en-US" %>


If you run the example now, you will get the output "English (United States)", which is the language of English, with a specific US culture. English comes in other flavors too, for instance British or Australian. en-US is considered a specific culture, where en (just English) is considered a neutral culture, since it's just a language, not specific to any country. Now, to see the difference between two cultures, try running this example:
<%@ Page Language="C#" Culture="en-US" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>CultureInfo demo</title>
</head>
<body>
    <form id="MainForm" runat="server">
        <% Response.Write("Current date, in a culture specific format: " + DateTime.Now.ToString()); %>
    </form>
</body>
</html>
Now, try changing the page Culture to a German one, like this:

<%@ Page Language="C#" Culture="de-DE" %>


You will see the exact same line of code output a different result, because it's culture dependant. But you can actually output a culturally aware date (or number or anything else) without changing the culture of the page. For instance, like this:

<% Response.Write("Current date, in a culture specific format: " + DateTime.Now.ToString(System.Globalization.CultureInfo.GetCultureInfo("de-DE").DateTimeFormat)); %>


We simply get a reference to a German culture, and then use it as a parameter to the ToString() method on the DateTime class. CultureInfo comes with a NumberFormat property for formatting numbers too. Obviously, formatting dates and numbers is just a small part of localizing an application, but the CultureInfo class is (or at least can be) the foundation of this process, mainly because it's so well integrated with the .NET framework, and in particular ASP.NET.

Culture vs. UICulture

This was all about the Culture property, but the Page class does come with another related property: The UICulture property. UI stands for User Interface, so in fact, this is the property we can use to identify the language used for the visual part of the page, while the Culture property is used for the non-UI stuff, like date and number formatting, sorting and so on. In lots of situations, you would want to use the same Culture and UICulture, but there are cases where you would want to separate these two, for instance when you want the text of a website to be localized, while still outputting a consistent date or number format, no matter where the user comes from.

Hello, localized world!

With the knowledge acquired from the previous chapters, let's try actually localizing some text, to see that it works. You should create a new project in Visual Web Developer or Visual Studio. You can use the default page added, or create a new one for the purpose. The content should look something like this:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Demo</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Label runat="server" ID="lblHelloWorld" Text="Hello, world!" />
    </form>
</body>
</html>
If you run it, you will get the good old "Hello, world!" message, in plain English as expected. Now let's add some localization magic to it. We will use local, implicit localization for this - both are new terms, which will be explained later on. For now, just right click on your project and from the Add ASP.NET folder sub menu, select App_LocalResources. This is the folder where we place local resources, each of them specific to a file in your project.

Now, right click this new folder, and add a new item. This should be a Resource file, and the name should be the same as your page, but with a .resx extension. For instance, I called my page Test.aspx, so my Resource file should be named Test.aspx.resx. This part is important - if we want ASP.NET to automatically map a resource file to a specific ASP.NET page, the names should be like this. This is our default resource file, used to keep the default version of our strings. Let's add a couple of other languages. Once again, the filename is used to map the resource file, so for instance, to add a German language file, the name should be <filename>.aspx.de.resx, or in the culture specific version: <filename>.aspx.de-DE.resx

I have added Test.aspx.de-DE.resx and Test.aspx.es-ES.resx, to translate the page into German and Spanish. Then I add a new row to Test.aspx.resx, with the name lblHelloWorld.Text. In my project, English is the default language, so I give this row a value of "Hello, world!". I then open Test.aspx.de-DE.resx, add a row with the same name as before, and set the value to "Hallo, Welt!". I do the same for Test.aspx.es-ES.resx, where I set the value to "Hola, mundo!". Your three resource files should now all have a row with the name of "lblHelloWorld.Text", and a localized version of the Hello world string.

Now, go back to our ASP.NET page and use the meta:resourcekey property on our Label control, to make it use our resource string. It should look like this:

<asp:Label runat="server" ID="lblHelloWorld" Text="Hello, world!" meta:resourcekey="lblHelloWorld" />


As you can see, I've used the same string as for the ID of the control. You probably remeber that we added a resource row with the name of "lblHelloWorld.Text". This corresponds to a control with the resource key of "lblHelloWorld", mapped to the Text property of this control. Now, try setting the UICulture property on your page and run the example:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" UICulture="de-DE" %>


The label is now in German. Change UICulture to "es-ES" and reload the page. It's now in Spanish. Then try changing it to something completely different, like fr-FR, and you will see our default language used instead, simply because we don't have a localized version of the string in French.

This was a simple example, to show you how it can work, but you need a bit more information about HOW it works. In the next couple of chapters we will look into local and global localization, as well as implicit and explicit localization. First up is the CultureInfo class though, since it's used heavily when doing localization.

Introduction to localization

According to Wikipedia, "Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text", and that is exactly what we'll look into in the next couple of chapters. Offering your website in other languages than the default one can be a big job, but fortunately, ASP.NET makes the process a lot easier.

There are quite a few concepts that you need to know about, right from the CultureInfo class to the concepts of local and global resources, as well as implicit and explicit localization. In the next couple of chapters, we will look into all of that, but first, let's see it in action, in our very own "Hello, localized world!" example.

FileUpload control

With ASP.NET, accepting file uploads from users has become extremely easy. With the FileUpload control, it can be done with a small amount of code lines, as you will see in the following example. However, please notice that there are security concerns to to consider when accepting files from users! Here is the markup required:
<form id="form1" runat="server">
    <asp:FileUpload id="FileUploadControl" runat="server" />
    <asp:Button runat="server" id="UploadButton" text="Upload" onclick="UploadButton_Click" />
    <br /><br />
    <asp:Label runat="server" id="StatusLabel" text="Upload status: " />
</form>
And here is the CodeBehind code required to handle the upload:
protected void UploadButton_Click(object sender, EventArgs e)
{
    if(FileUploadControl.HasFile)
    {
        try
        {
            string filename = Path.GetFileName(FileUploadControl.FileName);
            FileUploadControl.SaveAs(Server.MapPath("~/") + filename);
            StatusLabel.Text = "Upload status: File uploaded!";
        }
        catch(Exception ex)
        {
            StatusLabel.Text = "Upload status: The file could not be uploaded. The following error occured: " + ex.Message;
        }
    }
}
As you can see, it's all relatively simple. Once the UploadButton is clicked, we check to see if a file has been specified in the upload control. If it has, we use the FileUpload controls SaveAs method to save the file. We use the root of our project (we use the MapPath method to get this) as well as the name part of the path which the user specified. If everything goes okay, we notify the user by setting the Text property of the StatusLabel - if not, an exception will be thrown, and we notify the user as well.

This example will get the job done, but as you can see, nothing is checked. The user can upload any kind of file, and the size of the file is only limited by the server configuration. A more robust example could look like this:
protected void UploadButton_Click(object sender, EventArgs e)
{
    if(FileUploadControl.HasFile)
    {
        try
        {
            if(FileUploadControl.PostedFile.ContentType == "image/jpeg")
            {
                if(FileUploadControl.PostedFile.ContentLength < 102400)
                {
                    string filename = Path.GetFileName(FileUploadControl.FileName);
                    FileUploadControl.SaveAs(Server.MapPath("~/") + filename);
                    StatusLabel.Text = "Upload status: File uploaded!";
                }
                else
                    StatusLabel.Text = "Upload status: The file has to be less than 100 kb!";
            }
            else
                StatusLabel.Text = "Upload status: Only JPEG files are accepted!";
        }
        catch(Exception ex)
        {
            StatusLabel.Text = "Upload status: The file could not be uploaded. The following error occured: " + ex.Message;
        }
    }
}
Here we use the two properties, ContentLength and ContentType, to do some basic checking of the file which the user is trying to upload. The status messages should clearly indicate what they are all about, and you can change them to fit your needs.

Sending e-mails

Sending e-mails with ASP.NET is pretty straight forward. The .NET framework comes with an entire namespace for handling e-mails, the System.Net.Mail namespace. In the following examples, we will use two classes from this namespace: The MailMessage class, for the actual e-mail, and the SmtpClient class, for sending the e-mail.

As you may be aware, mails are sent through an SMTP server, and to send mails with the .NET framework, you will need access to an SMTP server. If you're testing things locally, the company that supplies your with Internet access, will usually have an SMTP server that you can use, and if you wish to use one of these examples on your actual website, the company that hosts your website will usually have an SMTP server that you can use. Go through the support pages to find the actual address - it's usually something along the lines of smtp.your-isp.com or mail.your-isp.com.

Once you have an accessible SMTP server, we're ready to send our very first e-mail. For the first example, all you need is an empty page, with the following code in the CodeBehind:


protected void Page_Load(object sender, EventArgs e)
{
    try
    {
        MailMessage mailMessage = new MailMessage();
        mailMessage.To.Add("your.own@mail-address.com");
        mailMessage.From = new MailAddress("another@mail-address.com");
        mailMessage.Subject = "ASP.NET e-mail test";
        mailMessage.Body = "Hello world,\n\nThis is an ASP.NET test e-mail!";
        SmtpClient smtpClient = new SmtpClient("smtp.your-isp.com");
        smtpClient.Send(mailMessage);
        Response.Write("E-mail sent!");
    }
    catch(Exception ex)
    {
        Response.Write("Could not send the e-mail - error: " + ex.Message);
    }
}

That's actually all you need to send an e-mail. We create a new MailMessage instance, add a new receiver, set the "From" address and the subject, and then we write a simple test message for the body of the e-mail. After that, we create a new instance of the SmtpClient, with the host address of the SMTP server that you may use as a parameter, and then we use the SmtpClient instance to shoot the e-mail out into cyberspace. The entire thing is surrounded by a try..catch block, just in case something goes wrong.

This was just a very basic example, but there are a lot of other options. Here is a short list with interesting ideas:

You can attach one or several files, simply by adding them to the Attachments collection. In this example, we attach a file called "image.jpg", located in the root of the ASP.NET website:

mailMessage.Attachments.Add(new Attachment(Server.MapPath("~/image.jpg")));

You can send to more than one person at the same time, simply by adding another e-mail address to the "To" collection, like this:

mailMessage.To.Add("your.own@mail-address.com"); mailMessage.To.Add("another@mail-address.com");

You can set a name for the sender - otherwise, only the e-mail address will be shown in the "From" column of the receivers e-mail client. For instance, like this:

mailMessage.From = new MailAddress("me@mail-address.com", "My Name");

You can send HTML e-mails, instead of the default plaintext mails, to use more complicated layouts. Here is a simple example:

mailMessage.IsBodyHtml = true; mailMessage.Body = "Hello <b>world!</b>";

You can use the CC and BCC fields, just like in regular e-mail messages, like this:

mailMessage.CC.Add("me@mail-address.com"); mailMessage.Bcc.Add("me2@mail-address.com");

You can set the priority of an e-mail, like this:

mailMessage.Priority = MailPriority.High;

ViewState

Another approach to saving data for the user, is the ViewState. As described elsewhere in this tutorial, the ViewState allows ASP.NET to repopulate form fields on each postback to the server, making sure that a form is not automatically cleared when the user hits the submit button. All this happens automatically, unless you turn it off, but you can actually use the ViewState for your own purposes as well. Please keep in mind though, that while cookies and sessions can be accessed from all your pages on your website, ViewState values are not carried between pages. Here is a simple example of using the ViewState to carry values between postbacks:
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>ViewState</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:TextBox runat="server" id="NameField" />
        <asp:Button runat="server" id="SubmitForm" onclick="SubmitForm_Click" text="Submit & set name" />
        <asp:Button runat="server" id="RefreshPage" text="Just submit" />
        <br /><br />
        Name retrieved from ViewState: <asp:Label runat="server" id="NameLabel" />
    </form> 
</body>
</html>
And the CodeBehind:
using System;
using System.Data;
using System.Web;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if(ViewState["NameOfUser"] != null)
            NameLabel.Text = ViewState["NameOfUser"].ToString();
        else
            NameLabel.Text = "Not set yet...";
    }

    protected void SubmitForm_Click(object sender, EventArgs e)
    {
        ViewState["NameOfUser"] = NameField.Text;
        NameLabel.Text = NameField.Text;
    }
}
Try running the project, enter your name in the textbox and press the first button. The name will be saved in the ViewState and set to the Label as well. No magic here at all. Now press the second button. This one does nothing at all actually, it just posts back to the server. As you will notice, the NameLabel still contains the name, but so does the textbox. The first thing is because of us, while the textbox is maintained by ASP.NET it self. Try deleting the value and pressing the second button again. You will see that the textbox is now cleared, but our name label keeps the name, because the value we saved to the ViewState is still there!

ViewState is pretty good for storing simple values for use in the form, but if you wish to save more complex data, and keep them from page to page, you should look into using cookies or sessions, as described in the previous chapters.

Sessions

Sessions can be used to store even complex data for the user just like cookies. Actually, sessions will use cookies to store the data, unless you explicitly tell it not to. Sessions can be used easily in ASP.NET with the Session object. We will re-use the cookie example, and use sessions instead. Keep in mind though, that sessions will expire after a certain amount of minutes, as configured in the web.config file. Markup code:
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Sessions</title>
</head>
<body runat="server" id="BodyTag">
    <form id="form1" runat="server">
    <asp:DropDownList runat="server" id="ColorSelector" autopostback="true" onselectedindexchanged="ColorSelector_IndexChanged">
        <asp:ListItem value="White" selected="True">Select color...</asp:ListItem>
        <asp:ListItem value="Red">Red</asp:ListItem>
        <asp:ListItem value="Green">Green</asp:ListItem>
        <asp:ListItem value="Blue">Blue</asp:ListItem>
    </asp:DropDownList>
    </form>
</body>
</html>
And here is the CodeBehind:
using System;
using System.Data;
using System.Web;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if(Session["BackgroundColor"] != null)
        {
            ColorSelector.SelectedValue = Session["BackgroundColor"].ToString();
            BodyTag.Style["background-color"] = ColorSelector.SelectedValue;
        }
    }

    protected void ColorSelector_IndexChanged(object sender, EventArgs e)
    {
        BodyTag.Style["background-color"] = ColorSelector.SelectedValue;
        Session["BackgroundColor"] = ColorSelector.SelectedValue;
    }
}
As you can see, the example doesn't need a lot of changes to use sessions instead of cookies. Please notice that session values are tied to an instance of your browser. If you close down the browser, the saved value(s) will usually be "lost". Also, if the webserver recycles the aspnet_wp.exe process, sessions are lost, since they are saved in memory as well. This can be avoided by saving session states on a separate StateServer or by saving to a SQL server, but that's beyond the scope of this article.

Before choosing a web host, always read reviews with web hosting comparison to make sure that they support SQL (not MySQL).

Cookies

Cookies are small pieces of text, stored on the client's computer to be used only by the website setting the cookies. This allows webapplications to save information for the user, and then re-use it on each page if needed. Here is an example where we save a users choice of background color:
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Cookies</title>
</head>
<body runat="server" id="BodyTag">
    <form id="form1" runat="server">
    <asp:DropDownList runat="server" id="ColorSelector" autopostback="true" onselectedindexchanged="ColorSelector_IndexChanged">
        <asp:ListItem value="White" selected="True">Select color...</asp:ListItem>
        <asp:ListItem value="Red">Red</asp:ListItem>
        <asp:ListItem value="Green">Green</asp:ListItem>
        <asp:ListItem value="Blue">Blue</asp:ListItem>
    </asp:DropDownList>
    </form>
</body>
</html>
The page simply contains a DropDownList control, which automatically posts back each time a new item is selected. It has 3 different colors, besides the default one, which is simply white. Once a new item is selected, the ColorSelector_IndexChanged method is fired, from our CodeBehind file:
using System;
using System.Data;
using System.Web;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if(Request.Cookies["BackgroundColor"] != null)
        {
            ColorSelector.SelectedValue = Request.Cookies["BackgroundColor"].Value;
            BodyTag.Style["background-color"] = ColorSelector.SelectedValue;
        }
    }

    protected void ColorSelector_IndexChanged(object sender, EventArgs e)
    {
        BodyTag.Style["background-color"] = ColorSelector.SelectedValue;
        HttpCookie cookie = new HttpCookie("BackgroundColor");
        cookie.Value = ColorSelector.SelectedValue;
        cookie.Expires = DateTime.Now.AddHours(1);
        Response.SetCookie(cookie);
    }
}
Okay, two different parts to be explained here. First, the Page_Load method, which is called on each page request. Here we check for a cookie to tell us which background color should be used. If we find it, we set the value of our dropdown list to reflect this, as well as the background color of the page, simply by accessing the style attribute of the body tag.

Then we have the ColorSelector_IndexChanged method, which is called each time the user selects a new color. Here we set the background color of the page, and then we create a cookie, to hold the value for us. We allow it to expire after one hour, and then we set it by calling the SetCookie method on the Response object.

Try running the example, and set a color. Now close the browser, and start it up again. You will see that the choice of color is saved, and it will remain saved for an hour. However, nothing prevents you from saving the choice for much longer. Simply add a bigger value to the expiry date, or set an absolute value for it.