Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[C#] Online Beta Key Distribution

Newbie Spellweaver
Joined
Dec 1, 2010
Messages
28
Reaction score
8
Preview


[TUTORIAL - Default.aspx]
So, you are presented with a challenge to create a 'Beta Key' application. Where to begin?

You need to realise what type of key you actually want to make. For this, I don't need a small key, or anything custom, because I'm going to send a link via email to the user. This means I can have any length, and in any order...

So, instead of tediously coding a Regex pattern, that will have random letters and numbers picked out from it into a compiled string (made me tired even while tying it), I used the fancy GUID method. This solves issues of Randomness, and Uniqueness.

Now, for the process (HA! No one simply CODEs Mordor).
A user needs to input their email, which will be stored into a database along with their Beta key..
Then, you need a page to check that beta key to the assigned email to verify if its all working... On the same page, you need the user to then create an account, so they can easily log in.

On the backend, we need an Admin page to view all the keys, create keys, bind them to emails, or leave them open!

..I am pretty sure that I have adequite commenting, but i will add a short description in case :)
Let us begin

ORDER:
[Title]
Code:
[Description]

Dates: dd/mm/yyyy

***********************************************************************
Before we get into the flow of things, Here are some initial things you need to know.

[B]Global Data Connection[/B]
[CODE]
using System;
using System.Data.SqlClient;
using System.Web;

/// <summary>
/// [DataConn.cs]
/// [03/01/2012]
/// [Darren Whitfield]
/// 
/// This will provide a global method to connect to a database via details on a config file.
/// When Connect() is called, it will connect to the database, and return any data, all at once.
/// 
/// Disconnect() will disconnect the application for the database, and destroy any data, maintaining security.
/// </summary>
/// 
public class DataConn
{
    private static SqlConnection _sqlConn;

    
    /// <summary>
    /// This will connect the application to the database, and return any further data.
    /// 
    /// You dont need to call Connect(), then datastring(connStr, Connect()),
    /// as the connect() in the data string is all you need.
    /// If you proceed to call Connect();, you will get a pooling error.
    /// </summary>
    /// <returns>
    /// _sqlConn as SqlConnection
    /// </returns>
    public static SqlConnection Connect()
    {
        //Store the connection details as a string
        string connstr =
            String.Format(@"Data Source=.\SQLEXPRESS;AttachDbFilename={0}\App_Data\Database.mdf;Integrated Security=True;User Instance=True", HttpContext.Current.Server.MapPath("~"));

        //Initialise the connection to the server using the connection string.
        _sqlConn = new SqlConnection(connstr);

        //Open the connection, we do this here so we can instantly be able to use SQL commands in the CODE.
        _sqlConn.Open();

        return _sqlConn;
    }
    
    /// <summary>
    /// Disconnects the Application from the database, and clears any other data.
    /// </summary>
    public static void Disconnect()
    {
        _sqlConn.Dispose();
        _sqlConn.Close();
    }
}

This is what I use as a global SQL accesser. This simply allows me to call the class-method, instead of copy-pasting the same CODE everywhere.


Databasing

Code:
*TABLES*

Key Storage
-ID (PK - Int - Auto Incrament by 1)
-Email (Varchar(50) - Allow Null)
-Hash (Varchar(50) - Allow Null)
-isUsed (tinyint)
-totalAllowed (int)
-isOpen (tinyint)
-Deleted (int)

Users
-ID (PK - Int - Auto Incrament by 1)
-Username (Varchar(50))
-Password (Varchar(50))
-Email (Varchar(50))

The database I use is local to the project itself. I use MsSql Compact server. This *should* allow a user to access the database, wherever they put the site.
Please note that this can be changed for any other server

***********************************************************************
Now on to the pages.

Default.aspx.cs
Code:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using System.Net.Mail;

/// <summary>
/// Beta Key Distributor - Generate and save
/// Darren Whitfield
/// 17/04/2012
/// 
/// This application will generate a random 'Beta' key,
/// then save that to a database, along with the requested
/// users email, to a local database.
/// 
/// The beta key will then be sent to that user via email.
/// 
/// Thanks to Smitty (RaGEZONE.com) for advice and changes!
/// </summary>
public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        var emailAddr = txtEmail.Text; //Get the user email from the text box
        var stringArray = Guid.NewGuid().ToString(); //Generate a unique string, based on GUID

        try //Incase there is a SQL Error...
        {
            //Check if email address is Valid
            if (IsEmail(emailAddr))
            {
                //Insert the relevant data into the database.
                string sqlStr = String.Format("INSERT INTO KeyStorage (Email, Hash, isUsed) VALUES (@email, @hash, 0)");
                var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) { CommandType = CommandType.Text };

                //*** Edited, thanks to Smitty, RaGEZONE
                sqlComm.Parameters.Add(new SqlParameter("@email", SqlDbType.VarChar, 50)).Value = emailAddr;
                sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = stringArray;

                sqlComm.ExecuteNonQuery(); //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

                DataConn.Disconnect(); //Make sure to terminate the current connection.

                SendEmail(emailAddr, stringArray);

                Response.Redirect("Result.aspx?id=1");
            }
            else
            {
                lblError.Text = "Please enter a valid email.";
                lblError.Visible = true;
            }


        }
        catch (SqlException) //If the email exists....
        {
            lblError.Text = "Database Error";
            lblError.Visible = true;
        }
    }

    /// <summary>
    /// Check weather the inputted email is a valid one, based on Regex
    /// </summary>
    /// <param name="inputEmail"></param>
    /// <returns>true, false</returns>
    private static bool IsEmail(string inputEmail)
    {
        const string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
                                @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
                                @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"; //Regex we need to validate against
        var re = new Regex(strRegex);
        if (re.IsMatch(inputEmail))
            return (true);

        return false;
    }

    /// <summary>
    /// Send an email to a valid user
    /// </summary>
    /// <param name="userEmail"></param>
    /// <param name="hashCode"></param>
    private void SendEmail(string userEmail, string hashCode)
    {
        var message = new MailMessage {From = new MailAddress("test@test.com")};

        message.To.Add(new MailAddress(userEmail)); //Who will recieve the mail?
        message.Subject = "Beta Key"; //Subject of the email.

        message.Body = "http://localhost:10013/BetaKeyDistributor/KeyVerify.aspx?hash=" + hashCode + "&email=" + userEmail;//Bulk of the message

        message.IsBodyHtml = true; //Set the format of the mail message body as HTML
        message.Priority = MailPriority.Normal; //Set the priority of the mail message to normal

        //You NEED to have an SMTP Server running in IIS.
        //***** Please note that this is running as a TEST. See web.config for details.
        var mailClient = new SmtpClient("127.0.0.1"); //Create an SMTP Client
        mailClient.Send(message); //Send our email


    }
}

What this page does is auto generate a 'Beta' key using GUID, stores it in the local DB - along with the users email - and then sends a link to the verification page to that email.
var message = new MailMessage {From = new MailAddress("test@test.com")};

message.To.Add(new MailAddress(userEmail)); //Who will recieve the mail?
message.Subject = "Beta Key"; //Subject of the email.

message.Body = "http://localhost:10013/BetaKeyDistributor/KeyVerify.aspx?hash=" + hashCode + "&email=" + userEmail;//Bulk of the message

message.IsBodyHtml = true; //Set the format of the mail message body as HTML
message.Priority = MailPriority.Normal; //Set the priority of the mail message to normal

//You NEED to have an SMTP Server running in IIS.
//***** Please note that this is running as a TEST. See web.config for details.
var mailClient = new SmtpClient("127.0.0.1"); //Create an SMTP Client
mailClient.Send(message); //Send our email

For this test, the email will be stored to the local machine (See web.config for details) instead of being sent.
The email includes the hash code, and users email address, so it can be easilly filled in on the key verification.


KeyVerify.aspx.cs

Code:
using System;
using System.Data;
using System.Data.SqlClient;

/// <summary>
/// Beta Key Distributor - Validator and Account Creator
/// Darren Whitfield
/// 18/04/2012
/// 
/// This applcation will compare the email to the beta key.
/// If they are both valid, the user will be able to create
/// an account.
/// </summary>
public partial class KeyVerify : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            //Get the initial Query String variables (If there aren't, its ok.)
            txtHashKey.Text = Request.QueryString["hash"];
            txtEmail.Text = Request.QueryString["email"];

            Session.Add("accepted", "false"); //If the key is valid
            Session.Add("count", "false"); //If the key is binded
            Session.Add("limit", 0); //How many uses left

            //Auto check to see if the hash is valid
            if (txtHashKey.Text != "" && txtEmail.Text != "")
            {
                Verify();
            }
        }
    }

    /// <summary>
    /// This will add the user to the local db, if the app confirms that everything is valid.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnRegister_Click(object sender, EventArgs e)
    {
        //This will make sure the person has clicked the Verify button, and that the key exists etc.
        if (Session["accepted"].ToString() == "true")
        {
            //Allow the user some informational access.
            lblVerified.Visible = true;
            lblVerified.Text = "BETA Key Verified";

            try
            {
                if(Session["count"].ToString() == "true")
                {
                    //Get the relevant data from the database.
                    const string sqlStr = @"UPDATE KeyStorage SET totalAllowed = @total WHERE (Hash=@hash)";
                    var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) { CommandType = CommandType.Text };

                    sqlComm.Parameters.Add(new SqlParameter("@total", SqlDbType.Int)).Value = Session["limit"];
                    sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = @txtHashKey.Text;

                    sqlComm.ExecuteNonQuery();
                    //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

                    DataConn.Disconnect(); //Make sure to terminate the current connection.
                }

                //Add the user to the DB
               // Manipulate.AddUser(txtUserName.Text, txtPassword.Text);

                //Update the is used...
                Manipulate.SetUsed(@txtHashKey.Text);

                Response.Redirect("Result.aspx?id=2");

            }
            catch (SqlException es) 
                //I know this supresses all errors, BUT, I have tried to break this without any supression, and it
                //works well. But if not, you will get a friendly message.
            {
                lblVerified.Text = es.Message;
            }
        }
            //If the user hasn't clicked 'Verify', this will happen.
        else
        {
            lblVerified.Visible = true;
            lblVerified.Text = "Please verify the hash key.";
        }
    }

    /// <summary>
    /// This will make sure that there is a key inputted, and that it checks out OK.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnVerify_Click(object sender, EventArgs e)
    {
        if (txtHashKey.Text != "")
        {
            //Verify the key.
            Verify();
        }
        else
        {
            //If there is no key inputted.
            lblVerified.Text = "Please enter/generate Beta Key";
        }
    }

    /// <summary>
    /// This is basically just a huge check. It calles the Manipulate() method for everything, and basically
    /// acts on what the output of it is.
    /// 
    /// This was created mainly to make the system fail-safe.
    /// 
    /// The code speaks for itself.
    /// </summary>
    private void Verify()
    {
        //This will check what the condition of the key is like.
        string response = Manipulate.CheckStatus(txtHashKey.Text);

        if (response == "keyUsed")
        {
            lblVerified.Visible = true;
            lblVerified.Text = "Beta key(s) already used.";
            Session["accepted"] = "false";
            Session["count"] = "false";
            Session["limit"] = "0";
        }
        else
        {
            if (response == "binded" && Manipulate.CheckIfHashIsValid(txtEmail.Text, txtHashKey.Text))
            {
                lblVerified.Visible = true;
                lblVerified.Text = "Beta key accepted";
                Session["accepted"] = "true";
                Session["count"] = "false";
                Session["limit"] = "1";
            }

            else if (response == "notExist")
            {
                lblVerified.Visible = true;
                lblVerified.Text = "Beta key does not exist.";
                Session["accepted"] = "false";
                Session["count"] = "false";
                Session["limit"] = "0";
            }

            else if (response == "binded")
            {
                lblVerified.Visible = true;
                lblVerified.Text = "Beta key binded to an email.";
                Session["accepted"] = "false";
                Session["count"] = "false";
                Session["limit"] = "1";
            }

            else
            {
                lblVerified.Visible = true;
                lblVerified.Text = response + " uses remaining.";
                Session["accepted"] = "true";
                Session["count"] = "true";
                Session["limit"] = response;
            }

        }
    }
}

So, we have the users key and email stored, and now we need something to validate all that, then allow the user to register to the site once the validation is completed!

Generally, a person will think some sort of magic happens, and the wizard of Oz mixes up a concoction to throw at your PC in the form of a web page... But I am here to disprove that..

Firstly, we need to easily allow the user to access his informational details. This is where the link in the email comes in handy...

From your ultra-perceptive eyes, I'm sure you would of noticed this in the previous tutorial
message.Body = "http://localhost:10013/BetaKeyDistributor/KeyVerify.aspx?hash=" + HashCode + "&email=" + UserEmail;

Woooo! Spooky stuff! As you could of seen, this is no ordinary URL! Oh no! This email contains a Request String!

"What is a query string?". I shall show you! A query string is something that comes after the usual URL pointer, to include additional info. Without anything reading from it, a query string will have no immediate effect on the page..

So, in this URL, you will see 'hash' and 'email' in the query string. This is an easy way to give the page information from an external source.

The main use of this page is to check the condition of the 'Beta' key. Otherwise, it addes a user to the local DB


Manipulate.cs

Code:
using System;
using System.Data;
using System.Data.SqlClient;

/// <summary>
/// [Manipulate]
/// [Darren Whitfield]
/// [23/04/2012]
/// 
/// This class will have all the manipulation methods for the application.
/// </summary>
public class Manipulate
{
    /// <summary>
    /// This method will check the database to see if a hash exists,
    /// is binded, and how many uses it has left.
    /// </summary>
    /// <param name="hash"> </param>
    public static string CheckStatus(string hash)
    {
        string isUsed;
        string totalAllowed;
        string isOpen;
        
        try
        {
            //Get the relevant data from the database.
            const string sqlStr = "SELECT * FROM KeyStorage WHERE (Hash=@hash)";
            var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) { CommandType = CommandType.Text };

            sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = hash;

            var rdr = sqlComm.ExecuteReader();
            //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

            rdr.Read(); //Make the reader get the data
            isUsed = rdr["isUsed"].ToString();
            totalAllowed = rdr["totalAllowed"].ToString();
            isOpen = rdr["isOpen"].ToString();
            rdr.Close(); //Readers are lazy.. They dont like it when you use them when they arent needed.
        }
        catch (Exception)
        {
            return "notExist";
        }

        if (isUsed == "0")
        {
            if (isOpen == "0")
            {
                return "binded";
            }
            return Int32.Parse(totalAllowed) <= 0 ? "keyUsed" : totalAllowed;
        }
        return "keyUsed";
    }

    /// <summary>
    /// This method will set the Hash's 'Deleted' tag to 1, hiding it from all pages, and making the ap think it does not exist.
    /// </summary>
    /// <param name="hash"></param>
    /// <returns></returns>
    public static int DeleteHash(string hash)
    {
        try
        {
            //Get the relevant data from the database.
            const string sqlStr = @"UPDATE KeyStorage SET Deleted = 1 WHERE (Hash=@hash)";
            var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) {CommandType = CommandType.Text};

            sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = hash;

            sqlComm.ExecuteNonQuery();

            DataConn.Disconnect();
            return 1;
        }

        catch (SqlException)
        {
            return 0;
        }
    }

    /// <summary>
    /// Check to see is the key is valid against the email address.
    /// </summary>
    /// <param name="emailAddress"></param>
    /// <param name="hashKey"></param>
    /// <returns></returns>
    public static bool CheckIfHashIsValid(string emailAddress, string hashKey)
    {
        //Get the relevant data from the database.
        const string sqlStr = @"SELECT Email FROM KeyStorage WHERE (Hash=@hash)";
        var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) { CommandType = CommandType.Text };

        sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = hashKey;

        var rdr = sqlComm.ExecuteReader(); //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

        rdr.Read(); //Make the reader get the data
        string currentEmail = rdr["Email"].ToString();
        rdr.Close(); //Readers are lazy.. They dont like it when you use them when they arent needed.

        DataConn.Disconnect(); //Make sure to terminate the current connection.

        if (currentEmail == emailAddress)
            return true;

        return false;
    }

    /// <summary>
    /// Add a user to the database.
    /// </summary>
    /// <param name="userName"></param>
    /// <param name="password"></param>
    public static void AddUser(string userName, string password)
    {
        //Get the relevant data from the database.
        const string sqlStr = @"INSERT INTO Users (Username, Password) VALUES (@username, @password)";
        var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) { CommandType = CommandType.Text };

        sqlComm.Parameters.Add(new SqlParameter("@username", SqlDbType.VarChar, 50)).Value = userName;
        sqlComm.Parameters.Add(new SqlParameter("@password", SqlDbType.VarChar, 50)).Value = password;

        sqlComm.ExecuteNonQuery();
        //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

        DataConn.Disconnect(); //Make sure to terminate the current connection.
    }

    /// <summary>
    /// Mark the hash key as used.
    /// </summary>
    /// <param name="hash"></param>
    public static string SetUsed(string hash)
    {
        int currentAllowed = getUsesRemaining(hash);
        int nextAllowed = currentAllowed - 1;

        if (currentAllowed == 1)
        {
            const string sqlStr = @"UPDATE KeyStorage SET isUsed = 1 WHERE (Hash=@hash)";
            //As for above...
            var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) {CommandType = CommandType.Text};

            sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = hash;

            sqlComm.ExecuteNonQuery();

            DataConn.Disconnect();

            return sqlStr;
        }
        else
        {
            string sqlStr = @"UPDATE KeyStorage SET totalAllowed = " + nextAllowed +" WHERE (Hash=@hash)";
            //As for above...
            var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) { CommandType = CommandType.Text };

            sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = hash;

            sqlComm.ExecuteNonQuery();

            DataConn.Disconnect();

            return sqlStr;
        }
    }

    /// <summary>
    /// Get the remaining amount of uses for the hash key.
    /// </summary>
    /// <param name="hash"></param>
    /// <returns></returns>
    public static int getUsesRemaining(string hash)
    {
        if (CheckStatus(hash) != "notExist")
        {
            const string sqlStr = @"SELECT totalAllowed FROM KeyStorage WHERE Hash=@hash";
            var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) {CommandType = CommandType.Text};

            sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = hash;

            var rdr = sqlComm.ExecuteReader();
            //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

            rdr.Read();
            int usage = Int32.Parse(rdr["totalAllowed"].ToString());
            rdr.Close();

            DataConn.Disconnect(); //Make sure to terminate the current connection.

            return usage;
        }
        return 0;
    }
}

This page is the main validator. Instead of having all this code on the KeyVerify page, I put it in a seperate file, so it can be called globally.
Strangely, this all worked the first time, so I am quite prouf of myself for that...
Darren, why are there no Coded quotes in this section??
I shal tell you young entertainment man!

This is a 'what you see is what you get' section. Stop being a zombi, and actually read the code! It is very straight forward, and nothing is hidden (more or less prostitute code).


Administrate.aspx.cs

Code:
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Net.Mail;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;

public partial class Administrate : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if(!IsPostBack)
        PopulatePage();
    }

    private void PopulatePage()
    {
        int betaCount = 0;

        //Get the relevant data from the database.
        string sqlStr =
            String.Format("SELECT * FROM KeyStorage");
        var sqlComm = new SqlCommand(sqlStr, DataConn.Connect());

        var rdr = sqlComm.ExecuteReader();
            //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

        //Create our array.
        while (rdr.Read())
        {
            if (rdr["Deleted"].ToString() == "0")
            {
                //Get the size of our array.
                betaCount = betaCount + 1;
            }
        }
        rdr.Close();
        var betaKeys = new string[betaCount,5]; //5 (4 + 1) because of all the coloumns we want to use, starting from 0.
        var aList = new ArrayList();

        //Populate the array
        rdr = sqlComm.ExecuteReader();
        int i = 0;

        while (rdr.Read())
        {
            if (rdr["Deleted"].ToString() == "0")
            {
                betaKeys[i, 0] = rdr["Hash"].ToString();
                betaKeys[i, 1] = rdr["isUsed"].ToString();
                betaKeys[i, 2] = rdr["totalAllowed"].ToString();
                betaKeys[i, 3] = rdr["isOpen"].ToString();
                betaKeys[i, 4] = rdr["Email"].ToString();

                i = i + 1;
            }
        }

        rdr.Close(); //Readers are lazy.. They dont like it when you use them when they arent needed.
        DataConn.Disconnect(); //Make sure to terminate the current connection.

        //Add array to a hash table
        for (int ii = 0; ii < betaCount; ii++)
        {
            var hs = new Hashtable
                         {
                             {"hash", betaKeys[ii, 0]},
                             {"used", betaKeys[ii, 1]},
                             {"total", betaKeys[ii, 2]},
                             {"open", betaKeys[ii, 3] == "0" ? "Yes" : "No"},
                             {"email", betaKeys[ii, 4] != "" ? betaKeys[ii, 4] : "[Open Key]"}
                         };
            aList.Add(hs);

        }

        rptBetaKeys.DataSource = aList;
        rptBetaKeys.DataBind();
    }

    /// <summary>
    /// Allow the user to select a binded, or open email.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void rdoSelectionList_SelectedIndexChanged(object sender, EventArgs e)
    {
        switch (rdoSelectionList.SelectedIndex)
        {
            case 1:
                txtBindEmail.Enabled = false;
                txtTotalAllowed.Enabled = true;
                break;
            default:
                txtBindEmail.Enabled = true;
                txtTotalAllowed.Enabled = false;
                break;
        }
    }

    protected void imgbtnGenerate_Click(object sender, EventArgs e)
    {
        txtBetaKey.Text = Guid.NewGuid().ToString(); //Generate a unique string, based on GUID
    }

    protected void btnAdd_Click(object sender, EventArgs e)
    {
        if (rdoSelectionList.SelectedIndex == 0)
        {
            try //Incase there is a SQL Error...
            {
                //Check if email address is Valid
                if (IsEmail(txtBindEmail.Text))
                {
                    //Insert the relevant data into the database.
                    const string sqlStr = @"INSERT INTO KeyStorage (Email, Hash) VALUES (@email, @hash)";
                    var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) {CommandType = CommandType.Text};

                    sqlComm.Parameters.Add(new SqlParameter("@email", SqlDbType.VarChar, 50)).Value = txtBindEmail.Text;
                    sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = txtBetaKey.Text;

                    sqlComm.ExecuteNonQuery();
                        //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

                    DataConn.Disconnect(); //Make sure to terminate the current connection.

                    SendEmail(txtBindEmail.Text, txtBetaKey.Text);

                    lblError.Text = "User added Successfully. Mail Sent.";
                }
                else
                {
                    lblError.Text = "Please enter a valid email.";
                    lblError.Visible = true;
                }

                Response.Redirect(Request.RawUrl);
            }
            catch (SqlException) //If the email exists....
            {
                lblError.Text = "Database Error";
                lblError.Visible = true;
            }
        }
        else
        {
            //Insert the relevant data into the database.
            const string sqlStr = "INSERT INTO KeyStorage (hash, totalAllowed, isOpen) VALUES (@hash, @total, 1)";
            var sqlComm = new SqlCommand(sqlStr, DataConn.Connect()) { CommandType = CommandType.Text };

            sqlComm.Parameters.Add(new SqlParameter("@total", SqlDbType.Int)).Value = txtTotalAllowed.Text;
            sqlComm.Parameters.Add(new SqlParameter("@hash", SqlDbType.VarChar, 50)).Value = txtBetaKey.Text;

            sqlComm.ExecuteNonQuery();
            //Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

            DataConn.Disconnect(); //Make sure to terminate the current connection.
            
            lblError.Text = "Key added successfully. Totall allowed: " + txtTotalAllowed.Text;

            Response.Redirect(Request.RawUrl);
        }

    }

    /// <summary>
    /// Check weather the inputted email is a valid one, based on Regex
    /// </summary>
    /// <param name="inputEmail"></param>
    /// <returns>true, false</returns>
    private static bool IsEmail(string inputEmail)
    {
        const string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
                                @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
                                @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"; //Regex we need to validate against
        var re = new Regex(strRegex);
        if (re.IsMatch(inputEmail))
            return (true);

        return false;
    }

    /// <summary>
    /// Send an email to a valid user
    /// </summary>
    /// <param name="userEmail"></param>
    /// <param name="hashCode"></param>
    private void SendEmail(string userEmail, string hashCode)
    {
        var message = new MailMessage {From = new MailAddress("test@test.com")};

        message.To.Add(new MailAddress(userEmail)); //Who will recieve the mail?
        message.Subject = "Beta Key"; //Subject of the email.

        message.Body = "http://localhost:10013/BetaKeyDistributor/KeyVerify.aspx?hash=" + Server.UrlEncode(hashCode) + "&email=" + userEmail;//Bulk of the message (Making sure the hash key is URL valid..

        message.IsBodyHtml = true; //Set the format of the mail message body as HTML
        message.Priority = MailPriority.Normal; //Set the priority of the mail message to normal

        //You NEED to have an SMTP Server running in IIS.
        //***** Please note that this is running as a TEST. See web.config for details.
        var mailClient = new SmtpClient("127.0.0.1"); //Create an SMTP Client
        mailClient.Send(message); //Send our email
    }

    protected void rptBetaKeys_ItemCommand(object source, RepeaterCommandEventArgs e)
    {
        //Remove the Hash key
        if (e.CommandName == "DeleteKey")
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                var lblHash = (Label)e.Item.FindControl("lblHashKey");

                lblError.Text = Manipulate.DeleteHash(lblHash.Text) == 1 ? "Entry Deleted." : "Error Deleting Entry.";
            }
        }
        
        Response.Redirect(Request.RawUrl);
    }
}

Last page! Well, last important one...

So we have the keys being distributed, validated, and users added. All is working up till now! But, your eager, power hungry mind is porbably assuming that there could be more...

Well there is!

If things never appealed to you now, well, this section allows you to be the King (non gender-related) of the system!

Aha.. Now you can add your very own custom keys, bind them to an email, or make it available for a certain amount of uses! (arousing?)

Again, the code speaks for itself. The only other thing it does is display all the keys (New and used) on the screen. This is done through a repeater control.
PHP:
<asp:Repeater ID="rptBetaKeys" runat="server" 
            onitemcommand="rptBetaKeys_ItemCommand">
            <HeaderTemplate>
                <table style="border-style: solid; border-width: 1px; width: 100%;  border-spacing: 0px;">

                <tr style="background: black; color: white; text-align: center; border-right-style: solid;">
                    
                    <th style="border-width: 1px; border-color: white; border-right-style: solid; width: 20px;"></th>
                    
                    <th style="border-width: 1px; border-color: white; border-right-style: solid; width: 200px">
                        Hash Key
                    </th>
                    <th style="border-width: 1px; border-color: white; border-right-style: solid; width: 90px;">
                        Is Used
                    </th>
                    <th style="border-width: 1px; border-color: white; border-right-style: solid; width: 90px;">
                        Uses Remaining
                    </th>
                    <th style="border-width: 1px; border-color: white; border-right-style: solid; width: 100px;">
                        Binded
                    </th>
                    <th style="width: 200px;">
                        Email Binded
                    </th>

                </tr>

            </HeaderTemplate>
            <ItemTemplate>
                
                <tr style="text-align: center">
                    <td style="width: 20px">
                        <asp:ImageButton ID="imgBtnDelete" runat="server" CommandName="DeleteKey" ImageUrl="~/images/cross.png" />
                    </td>
                    <td style="width: 200px;">
                        <asp:TextBox ID="txtHash" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[hash]") %> ReadOnly="True" Width="250"></asp:TextBox>
                    </td>
                    <td style="width: 90px;">
                        <asp:Label ID="lblUsed" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[used]")%>></asp:Label>
                    </td>
                    <td style="width: 90px;">
                        <asp:Label ID="lblTotal" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[total]")%>></asp:Label>
                    </td>
                    <td style="width: 100px;">
                        <asp:Label ID="lblIsOpen" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[open]")%>></asp:Label>
                    </td>
                    <td style="width: 200px;">
                        <asp:Label ID="lblEmail" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[email]") %>></asp:Label>
                    </td>
                </tr>
            
            </ItemTemplate>
            <AlternatingItemTemplate>
                <tr style="text-align: center; background-color: #F2F2F2;">
                    <td style="width: 20px">
                        <asp:ImageButton ID="imgBtnDelete" runat="server" CommandName="DeleteKey" ImageUrl="~/images/cross.png" />
                    </td>
                    <td style="width: 200px;">
                        <asp:TextBox ID="txtHash" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[hash]") %> ReadOnly="True" Width="250"></asp:TextBox>
                    </td>
                    <td style="width: 90px;">
                        <asp:Label ID="lblUsed" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[used]")%>></asp:Label>
                    </td>
                    <td style="width: 90px;">
                        <asp:Label ID="lblTotal" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[total]")%>></asp:Label>
                    </td>
                    <td style="width: 100px;">
                        <asp:Label ID="lblIsOpen" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[open]")%>></asp:Label>
                    </td>
                    <td style="width: 200px;">
                        <asp:Label ID="lblEmail" runat="server" Text=<%# DataBinder.Eval(Container.DataItem, "[email]") %>></asp:Label>
                    </td>
                </tr>
            </AlternatingItemTemplate>
            <FooterTemplate>
               </table> 
            </FooterTemplate>
        </asp:Repeater>
Is that... Front end code...????!!!????!!1one!
Yes it is, person with the weird nose!

Repeaters are hard to mimic, so I thought I should just show you!

private void PopulatePage()
{
int betaCount = 0;

//Get the relevant data from the database.
string sqlStr =
String.Format("SELECT * FROM KeyStorage");
var sqlComm = new SqlCommand(sqlStr, DataConn.Connect());

var rdr = sqlComm.ExecuteReader();
//Make the magic happen. (Magic as in someones work, not the idiotic "WTF is happening? Oh well, I dont care" ### that everyone processes.)

//Create our array.
while (rdr.Read())
{
if (rdr["Deleted"].ToString() == "0")
{
//Get the size of our array.
betaCount = betaCount + 1;
}
}
rdr.Close();
var betaKeys = new string[betaCount,5]; //5 (4 + 1) because of all the coloumns we want to use, starting from 0.
var aList = new ArrayList();

//Populate the array
rdr = sqlComm.ExecuteReader();
int i = 0;

while (rdr.Read())
{
if (rdr["Deleted"].ToString() == "0")
{
betaKeys[i, 0] = rdr["Hash"].ToString();
betaKeys[i, 1] = rdr["isUsed"].ToString();
betaKeys[i, 2] = rdr["totalAllowed"].ToString();
betaKeys[i, 3] = rdr["isOpen"].ToString();
betaKeys[i, 4] = rdr["Email"].ToString();

i = i + 1;
}
}

rdr.Close(); //Readers are lazy.. They dont like it when you use them when they arent needed.
DataConn.Disconnect(); //Make sure to terminate the current connection.

//Add array to a hash table
for (int ii = 0; ii < betaCount; ii++)
{
var hs = new Hashtable
{
{"hash", betaKeys[ii, 0]},
{"used", betaKeys[ii, 1]},
{"total", betaKeys[ii, 2]},
{"open", betaKeys[ii, 3] == "0" ? "Yes" : "No"},
{"email", betaKeys[ii, 4] != "" ? betaKeys[ii, 4] : "[Open Key]"}
};
aList.Add(hs);

}

rptBetaKeys.DataSource = aList;
rptBetaKeys.DataBind();
}

This method makes the repeater what it is.
It takes data from the local DB using a SQL Reader, Binds it to an array, adds that array to a hash table, then adds that table to an array list!
Haha, smple!

Unfortunatly, the repeater needs that process in order to work! Get used to it!


Result.aspx.cs

Code:
using System;

/// <summary>
/// Result
/// Darren Whitfield
/// 20/04/2012
/// 
/// This page will be the lander after any task is made.
/// 
/// It will display an output based on the query string.
/// </summary>
public partial class Result : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        int response = Int32.Parse(Request.QueryString["id"]);

        if(response == 1) //Sent the key
        {
            lblTitle.Text = "Beta Key Sent!";
            lblBody.Text = "Please check your email for further details.";
        }
        else if (response == 2) //Registered user
        {
            lblTitle.Text = "User registration successful";
            lblBody.Text = "You may now log in to the site with the set credentials.";
        }
    }
}

...As if you dont know!

Its just a happy place for all your dreams to be turned into nightmares.. Nothing to do here!


***********************************************************************

Additional Notes

Nothing gets Deleted permanently. Please, as a coder, remember to always do this.
Keys are simply marked with a deletion (IsDeleted = 1 in the DB), so it will be hidden in the page.

***********************************************************************

Please leave comments :D == "Leave compliments, criticism and ideas below"...
 
Last edited:
Newbie Spellweaver
Joined
Dec 1, 2010
Messages
28
Reaction score
8
Yeah, I see that I may of sounded like "Rawr! Give me attentions now!"... But I honestly didn't mean that :)

Its more like, "Leave compliments, criticism and ideas below"...

Thanks for blowing your 300th on me ;)

Next, I shall code a message system that can traverse data back in time, so I may of helped you back then :D

Happy coding :)
 
Back
Top