Friday, January 6, 2012

C# and ASP.NET - Parsing Console Arguments


It seems like the easiest things are sometimes the hardest when you are out of practice.  I'm sure that's a quote from somewhere, but I can tell you it's true.


So, without any fan fair here is a simple way to parse those pesky console arguments:

    public class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //parse out console args
                bool allowExecution = true;
                string appDescription = "Greatest Console Ever!";


                for (int i = 0; i < args.Length; i++)
                {
                    string arg = args[i];
                    switch (arg)
                    {
                        case "-description":
                             appDescription  = args[i + 1]
                             i++;
                            break;


                        default:
                            allowExecution = false;
                            Console.WriteLine("invalid arguments");
                            break;
                    }
                }


                //Execute some console command
                if (allowExecution)
                {
                     console.WriteLine(appDescription);
                }


                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

So when you run your application from the command line you would say myapp.exe -description "party rocking"


And that's it folks.  Happy arg parsing.

-Matt

Wednesday, August 24, 2011

C# and ASP.NET - Session State Alternative - Shared Hosting

After many long hours of trying to figure out why my session state information was being dropped randomly while using a shared hosting company I finally gave up and wrote my own way to persist session information in a database.

My Problem:
Many shared hosting company recycle their IIS virtual memory at a rate that was unpredictable and therefor lose any In-Process session state information without warning.  Because most shared hosting companies do not allow you to use the ASP.NET State Service you are really only left the the option of the built in ASP.NET SQLServer Session State mode.

My Solution:
Use a database to store user information.  This is not to say you can't use the built in ASP.NET SQLServer session state mode.  However, by using that you may find yourself in need of purchasing a separate database instance on your shared service provider once your site gets large enough because of the overhead it has the possibility of creating.


Here is what you need to do to implement this:
Create a database (use whatever name you like).

Now create two tables:  User and LoginKey

User Table Columns:

UserID_PK int Primary Key/Identity
Email varchar(75)
Password varchar(20)

LoginKey Table Columns:

LoginKeyID_PK int Primary Key/Identity
LoginKeyGUID varchar(39)
UserID_FK int
DateLoggedIn datetime
IPAddress varchar(15)



Now that you have your tables in place you need a few stored procedures to Get/Update/Delete the data in them.

Stored procedure to Create A User:

-- =============================================
-- Author: Matt Cramer, CramerCode.com
-- Create date:        --
-- Description: Create a user account
-- =============================================
CREATEPROCEDURE [dbo].[CreateNewUser]
@Email varchar(75),
@Password varchar(20),
@IPAddress varchar(15)
AS


DECLARE @UserID int
DECLARE @EmailUsed bit
DECLARE @LoginKey uniqueidentifier
SET @LoginKey = NEWID()
SET @EmailUsed = 0


IF EXISTS( SELECT 
UserID_PK
FROM
[User] WITH (NOLOCK)
WHERE
Email = @Email)
BEGIN
SET @EmailUsed = 1


SELECT @EmailUsed AS EmailUsed, '' AS LoginKey
END


IF(@EmailUsed = 0)
BEGIN
INSERT INTO [User]
(
Email,
[Password]
)
VALUES
(
@Email,
@Password
)


SET @UserID = SCOPE_IDENTITY()


INSERT INTO LoginKey
(
LoginKeyGUID,
UserID_FK,
IPAddress
)
VALUES
(
@LoginKey,
@UserID,
@IPAddress
)


SELECT @EmailUsed AS EmailUsed, @LoginKey AS LoginKey
END


The CreateNewUser stored procedure does exactly what it says it does.  It creates a new user.  You would use this on a signup page most likely.  You will also notice that it returns two columns: EmailUsed, and LoginKey.  EmailUsed lets you know if the email address they are using to sign up with has already been taken and thus a user was not created in the database.  The other column, LoginKey, is used to pass between pages and used to retrieve user information as the user clicks around the site.  This column is in the form of a GUID and needs to be stored in either the query string or a hidden field.

Note:  hidden field is preferred due to being able to encrypt it if you need to via SSL.






Stored procedure to Login A User:

-- =============================================
-- Author: Matt Cramer, CramerCode.com
-- Create date:       -----
-- Description: Log in user
-- =============================================
ALTER PROCEDURE [dbo].[LoginUser]
@Email varchar(75),
@Password varchar(20),
@IPAddress varchar(15)
AS
DECLARE @UserID int


IF EXISTS( SELECT
UserID_PK
FROM
[User] WITH (NOLOCK)
WHERE
Email = @Email
AND
[Password] = @Password)
BEGIN


SET @UserID = ( SELECT
UserID_PK
FROM
[User] WITH (NOLOCK)
WHERE
Email = @Email
AND
[Password] = @Password)


DELETE FROM LoginKey
WHERE
UserID_FK = @UserID


INSERT INTO LoginKey
(
UserID_FK,
IPAddress
)
VALUES
(
@UserID,
@IPAddress
)


SELECT 
LoginKeyGUID
FROM
LoginKey WITH (NOLOCK)
WHERE
LoginKeyID_PK = SCOPE_IDENTITY()
END
ELSE
BEGIN
SELECT ''
END


The LoginUser stored procedure is simple enough.  It takes Email, Password, and IPAddress (I'll talk about this later) as parameters to verify if a user for that email/password combination exists in the User table.  If the user is successfully logged in a row will be added to the LoginKey table and the GUID (or login key) will be returned to you.  Again this column is in the form of a GUID and needs to be stored in either the query string or a hidden field and passed around the site as the user clicks around.



Stored procedure to Verify a User is logged in:

-- =============================================
-- Author: Matt Cramer, CramerCode.com
-- Create date:       ----
-- Description: Verify login
-- =============================================
ALTER PROCEDURE [dbo].[VerifyLogin]
@Key uniqueidentifier,
@IPAddress varchar(15)
AS


IF EXISTS( SELECT
LoginKeyID_PK
FROM
LoginKey With (NOLOCK)
WHERE
LoginKeyGUID = @Key
AND
IPAddress = @IPAddress)
BEGIN
SELECT 'LoggedIn'
END
ELSE
BEGIN
SELECT 'NotLoggedIn'
END


This should be called at the beginning of any request to verify the user is who they say they are.  This stored procedure takes a Key (the login key GUID), and the IP address of the user that is making the request.  The response from this stored procedure is simply "LoggedIn" or "NotLoggedIn" based on if the user information was found in the LoginKey table.

Okay, so why the IP address parameter?  This is just an extra layer of security to help prevent a session hijack.  It is not really needed if you are using SSL and storing the login key in a hidden field.  However, if you put the login key in the query string it will go across most proxies as clear text even if you are using SSL.



Last stored procedure will Log a User out:
-- =============================================
-- Author: Matt Cramer, CramerCode.com
-- Create date:        ----
-- Description: Log out user
-- =============================================
ALTER PROCEDURE [dbo].[LogoutUser]
@Key uniqueidentifier
AS


DELETE FROM LoginKey
WHERE
LoginKeyGUID = @Key

This stored procedure should be called when a user wants to log out.


Putting it all together the logic looks like this:
user comes to site ->
user creates an account (CreateNewUser ) ->
user gets redirected to an account page and clicks around (VerifyLogin) for each page visited ->
user logs out for the day (LogoutUser) ->
user comes back the next day and logs in (LoginUser)



Final thoughts:
This technique was very popular before people got hooked on using the Session object to clog up the IIS pipeline.  This technique enforces the idea of serializable information being stored in either the IO or in the database in small chunks.

-Matt

Thursday, January 13, 2011

ASP.NET MVC - The developer is back in control

ASP.NET MVC excites me more than just about anything Microsoft has released in the past 5 years (well... I do like Silverlight).  As I am new to MVC development, I am very familiar with classic forms of Microsoft web development (classic ASP, and ASP.NET).

A bit of history is in order here
Back in the nineteen hundred and nineties Microsoft released ASP.  At the time it was a very procedural VB scripting language.  You didn't have objects really (COM was available, but not really the same thing) and  debugging was a nightmare.  Anyone other than me remember writing "Response.Write...." 9863454 times trying to figure out where a logic error was?

A little after ASP 3.0 was released Microsoft released ASP.Net 1.0.  All of a sudden all the VB script programmers were in a rough spot.  ASP.Net was a totally new concept in web development.  Not only did you have to learn a new language (VB or C#) but you also lost a lot of control over what was actually rendered to the browser.

So now there is yet another new and very different way of development?
That's right folks!  It's time to role up those sleeves again and dive in.  Only this time Microsoft didn't make any language changes so the learning curve is a bit smaller.  When I first looked at MVC I was a bit skeptical (because who wants to relearn everything they thought they knew about web development....again).  As I was reading about MVC it was like turning over flat rocks in a field hoping there wasn't a snake underneath.  Slowly over time I realized that Microsoft had done something so wonderful that instead of being afraid of what I would find I was destroying all the information I could find on the subject!  I was back in control of exactly what was to be rendered on a page and not only that, I was able to take advantage of object oriented design patterns too. To top it all off MVC allows for better debugging and Unit Testing of my code.

FINALLY!  The developer is back in control!

-M

Thursday, December 16, 2010

C# and ASP.Net - Searching for a control recursively

At some point during my programming career I found I needed to search for a control on a page but had no way to know who the control's parent would be.  So after a little thinking I thought to myself "what if I could just search any parent and it's children recursively?".

This would give me the flexibility to search a specific parent control like a panel or an entire master page if needed.  So by adding the following methods to a "Search" class (or whatever you want to name it) you too can have this functionality:

    /// <summary>
    /// Searches through all child controls looking for the control name specified
    /// </summary>
    /// <param name="parentControl">
    /// Control - the control to search
    /// </param>
    /// <param name="controlName">
    /// string - control name to find
    /// </param>
    /// <param name="control">
    /// Control - control to bind to the found control
    /// </param>
    public static void FindControl(Control parentControl, string controlName, ref Control control)
    {
        if (control.ID == null)
        {
            SearchControl(parentControl, controlName, ref control);
        }


        if (parentControl.HasControls())
        {
            foreach (Control item in parentControl.Controls)
            {
                FindControl(item, controlName, ref control);
            }
        }
    }


    /// <summary>
    /// Helper method for FindControl
    /// </summary>
    private static void SearchControl(Control parentControl, string controlName, ref Control control)
    {
        if (parentControl.FindControl(controlName) != null)
        {
            control = parentControl.FindControl(controlName);
        }
    }


Pretty simple yeah?

So now you just have to call FindControl and pass in the parent control to search.  It will then search all of it's children parent controls looking for the control by name.  Once it finds the control its looking for it will assign a reference to the ref Control control parameter.  If it doesn't find it then the control you passed in will still be null or set to whatever it is you set it to before passing it in.

Happy control searching!

-Matt

Tuesday, December 14, 2010

C# and ASP.Net - Reusable data layer

Creating a data layer can be a fairly complex issue.  There are many options to choose from, and keeping business code removed from your data layer can be bothersome.

The example code below will describe how to create an abstract database call using MS SQL Server.  This technique will demonstrate how to keep the data layer far far away from the business code.  Enjoy =)

First thing we need to do is add a connection string to the database we want access to using the web.config file.  In your web.config file create a "connectionstring" element like this:

<configuration>
    <configSections>
    ........
    <connectionStrings>
      <add name="SiteConnectionString" connectionString="Server=..;Database=..;Uid=..;Password=..;"/>
    </connectionStrings>
.......

Now that we have a connection string ready to go we can build the abstract class to take advantage of it like this:


using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;


public abstract class DatabaseCall : IDisposable
{
    //Create a connection
    private SqlConnection sqlConnection = new SqlConnection();


    //Create a command
    private SqlCommand sqlCommand = new SqlCommand();



    //Create a transaction
    private SqlTransaction sqlTransaction; 

.......

We need this class to disposed of itself correctly so the IDisposable interface has been added to handle that.  So let's add some clean up code to the class:


    public void Dispose()
    {
        if (sqlConnection != null)
        {
            sqlConnection.Close();
            sqlConnection.Dispose();
        }
        if (sqlCommand != null)
        {
            sqlCommand.Dispose();
        }
        if (sqlTransaction != null)
        {
            sqlTransaction.Dispose();
        }
    }




Now that we can clean up our mess after we instantiate the class, let's create our constructor for the class:


    public DatabaseCall(bool hasTransaction, string connectionString)
    {
        this.SetConnection = connectionString;
        sqlCommand.Connection = sqlConnection;
        sqlConnection.Open();
        sqlCommand.CommandTimeout = 30;
        sqlCommand.CommandType = CommandType.StoredProcedure;
        if (hasTransaction)
        {
            sqlTransaction = sqlConnection.BeginTransaction();
            sqlCommand.Transaction = sqlTransaction;
        }
    }


The constructor is simple enough.  You tell it if the database calls from the derived class will be using transactions, and which connection string to use (from the web.config).

Now that we have all that taken care of we can create a simple database call method like so:


    public int ExecuteNonQuery(string procedureName, Hashtable hashtable)
    {
        try
        {
            //Clear parameters and set stored procedure to execute
            sqlCommand.Parameters.Clear();
            sqlCommand.CommandText = procedureName;


            AssignParameters(ref sqlCommand, hashtable);


            return sqlCommand.ExecuteNonQuery();
        }
        catch (SqlException sqlex)
        {
            throw sqlex;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }


The ExecuteNonQuery method takes a stored procedure name and a hashtable of parameter values and sends that information to the database after a bit of manipulation from the AssignParameters method does it's magic.  Of course if there are any exceptions they are thrown up the stack to be captured by a process of your choosing.

Now that we can call a stored procedure we need to know how the parameters are pulled out of the hashtable.  This brings us to the AssignParameters method:


    private void AssignParameters(ref SqlCommand sqlCommand, Hashtable hashtable)
    {
        SqlCommandBuilder.DeriveParameters(sqlCommand);


        //Check for a parameter match and set the value
        foreach (SqlParameter parameter in sqlCommand.Parameters)
        {
            if (hashtable.ContainsKey(parameter.ParameterName))
            {
                parameter.Value = hashtable[parameter.ParameterName];
            }
        }
    }



The AssignParameters method uses the SqlCommandBuilder.DeriveParameters() method to pull out parameter information from the database for the stored procedure stored in the SqlCommand object.  Once that information is returned from the database we can go through the hashtable and find the stored procedures by name and create a parameter collection.  After all that information is gathered you can then call the ExecuteNonQuery() method in ADO.NET which executes the stored procedure and returns the number of rows affected by the call.

So now let's derive this puppy and see how it works in a real application.  We will need to build a derived class for each connection string in our web.config file (in this case just one).  So let's create the derived class now:

public class RunDabaseCall : DatabaseCall
{

    public RunDabaseCall ()
        : base(false, ConfigurationManager.ConnectionStrings["SiteConnectionString"].ConnectionString)
    { }
}

Whew!  What a monster class!  Now to run a database call from your application simply do this:

int Main(args[])
{

        Hashtable hash = new Hashtable();
        RunDabaseCall runDatabaseCall = new RunDabaseCall();


       hash["@parameter1"] = "some data";
       runDatabaseCall.ExecuteNonQuery("stored procedure name", hash);
      
      runDatabaseCall.Dispose();

}


You want to run this in a transaction!?  Yer crazy, but I like you... Here's all you have to do.  Add this bit to the DatabaseCall class:


    public void CommittTransaction()
    {
        try
        {
            if (sqlTransaction != null)
            {
                sqlTransaction.Commit();
            }
        }
        catch (SqlException sqlex)
        {
            throw sqlex;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

AND:


    public void RollBackTransaction()
    {
        try
        {
            sqlTransaction.Rollback();
        }
        catch (SqlException sqlex)
        {
            throw sqlex;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }



Now change the derived class RunDatabaseCall like this:


public class RunDabaseCall : DatabaseCall
{
    public RunDabaseCall ()
        : base(true, ConfigurationManager.ConnectionStrings["SiteConnectionString"].ConnectionString)
    { }
}

Now when you run your database calls in your application you will be running them in a database transaction:


int Main(args[])
{
        Hashtable hash = new Hashtable();
        RunDabaseCall runDatabaseCall = new RunDabaseCall();

       hash["@parameter1"] = "some data";            <------------------ CASE SenSItiVE
       runDatabaseCall.ExecuteNonQuery("", hash);

      runDatabaseCall.CommitTransaction();
      runDatabaseCall.Dispose();
}

If there are any errors or any reasons to roll back your transaction like it never happened just call the RollBackTransaction() method.

Thats it!  Happy database calling.

-Matt

Wednesday, November 17, 2010

OMG! that's so elegant! or is it?

Ah yes, the term used by developers that pretty much means "I found a cool way to make this reusable, or better, or check this out, or ... etc...".

This term is so often used in the development community that it is nearly meaningless.  You might as well paint one house blue and one house red, and call the red house elegant.  Elegant is an opinion so when you hear the term [elegant] take it with a grain of salt.  What matters when you are developing an application is that the application WORKS (uh oh, I hear the eyes of senior developers rolling).  Yes, of course you want to think through your process and try to make all the parts and pieces as reusable as possible.  However, that doesn't mean your way is wrong because someone tacked the word "elegant" to something they worked on, or look at your code like they just got punched in the stomach because it doesn't match their way of coding.

Here is an example:  Let's say you have a database call that relies on stored procedures as the command source.  How many ways can you think of to make this work?  I suppose you could create a constant "SPROC" variable and assign the stored procedure to it, and assign it to the command text where ever you need to call that stored procedure.  On the other hand you could just as easily say command source = stored procedure.

So which way is better?  It's a simple matter of choice.  However, I bet a certain percentage of people out there have already made up their minds on which is "better", and how their way, not represented in this example, would be "better".  And I imagine there are equally that many excuses as to why.

In conclusion I believe development is a bit like art.  Only the person, or team can decide the elegance of a bit of code.

-Matt