# Friday, April 27, 2012

Here is Richard Campbell’s September 2009 presentation at the Great Lakes Area .NET User Group (GANG). Richard described what developers can do to make their ASP.NET applications more scalable.

Friday, April 27, 2012 3:13:00 PM (GMT Daylight Time, UTC+01:00)
# Wednesday, April 25, 2012

Episode 208

Joe Guadagno on INETA

Wednesday, April 25, 2012 7:10:00 PM (GMT Daylight Time, UTC+01:00)
# Monday, April 23, 2012
Monday, April 23, 2012 9:37:00 PM (GMT Daylight Time, UTC+01:00)
# Sunday, April 22, 2012

This year, Michael Eaton and his colleagues hosted the 4th annual Kalamazoo X conference. I have attended all 4 years and I have to say this was the best one. For those who haven’t yet heard of Kalamazoo X, it is a conference targeted at software developers, but the topics focus on the softer skills (i.e., the non-technical skills) required in your career. Each presentation is only 30 minutes long, which keeps things moving very rapidly. A single track provides a shared experience for all attendees. Every presentation was excellent and the room was packed. Speakers would often reference a presentation from earlier in the day.

Below are my notes from the sessions I attended.

Joe O'Brien
People Patterns
Packed a lot of great ideas
Never seen a project fail for technical reasons.
Corollary: Never seen a project SUCCEED for technical reasons.
Deliver bad news quickly

Laura Bergells
The People You Like the Least are the People You Need the Most
Teams require different personality types
Idea people (Putting the "Fun" in "DYSFUNCTIONAL") and rational people (Putting the "No" in "INNOVATION")

Suzan Bond
Intuition: Your Very Own Super Power
Learn to understand intuition and trust yourself.
Takes guts
OK to find ways to back up intuition.

Leon Gersing
Going Gonzo – an exploration of cultures in software development
Allow yourself to separate from the dominant culture and its associated dogma.
Drew inspiration from Hunter Thompson, Frank Zappa, and Georges Seurat.
"Most people doing Agile today are actually doing Waterfall with Agile terms. Agile is dead."
More important to be right than to be wise. Understand the problems you are solving.

Tim Wingfield
Your Career is Yours
Watch Sir Ken Robinson's TED talk
Ask Why? Does my customer really need this feature?
Coding Katas: Practice how to code.
Need to build trust. Be honest.
Work/Life balance: You need to enjoy your career; not endure your career.

Justin Searls
The Mythical Team-Month
If you are going to fail, fail quickly.
We are conditioned to avoid failure
Finding great developers:
Most traits are non-technical
Look for one who can succeed without you.

Sunday, April 22, 2012 3:25:00 PM (GMT Daylight Time, UTC+01:00)
# Wednesday, April 18, 2012
Wednesday, April 18, 2012 3:20:00 PM (GMT Daylight Time, UTC+01:00)
# Monday, April 16, 2012
Monday, April 16, 2012 4:02:00 PM (GMT Daylight Time, UTC+01:00)
# Friday, April 13, 2012

SQL Injection  is one of the most frequently-exploited vulnerabilities in the software world. It refers to user-entered data making its way into commands sent to back-end systems. It is common because so many developers are unaware of the risk and how to mitigate it.

Most of the applications I work with read from and write to a relational database, such as Microsoft SQL Server.  I frequently run across ADO.NET code like the following:

string lastName = "'Adams'";
string sql = "Select * from dbo.Customer where LastName = '" + lastName + "'";
string connString = ConfigurationManager.ConnectionStrings["LocalConn"].ConnectionString;
using (var conn = new SqlConnection(connString))
{
    conn.Open();
    var cmd = conn.CreateCommand();
    cmd.CommandText = sql;
    SqlDataReader reader = cmd.ExecuteReader();
    while (reader.Read())
    {
        Console.WriteLine("Bad Name: {0} {1}", reader["FirstName"], reader["LastName"]);
    }
}

This code is designed to call a stored procedure like the following:

CREATE PROCEDURE [dbo].[GetCustomersByFirstName]
    @FirstName NVARCHAR(50)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    SET NOCOUNT ON;

    SELECT 
            Id, 
            FirstName, 
            LastName
        FROM dbo.Customer
        WHERE FirstName = @FirstName
        ORDER BY Id
END

GO

This method of code has several disadvantages

  1. This code is not optimal because SQL Server does not have a chance to reuse a cached query plan unless the user happens to send the exact same text into SQL Server.
  2. The string concatenation opens the system to SQL Injection attacks.

A SQL Injection Attack is an attempt by an unscrupulous user to pass malicious commands to a database. In the above example, imagine that the variable x was provided by a user inputting text into a text box on a web age. An evil user might type something like

"Smith';DROP TABLE Customer;//"

If that code runs with sufficient permissions, it would wreak havoc on your database. The following query would be passed to SQL Server.
Select * from dbo.Customer where LastName = 'Smith';DROP Table Customer;//'

Clearly, dropping the customer table is not what your code is intended to do.

Many of you will read the above example and decide that you are safe because

  1. Your web code runs under a context with insufficient privileges to drop a table; and
  2. You are validating all user inputs to ensure a user cannot enter anything bad.

There are problems with this reasoning.

  1. A clever hacker can sometimes trick a user into running code under elevated privileges. Often there are multiple steps to an attack.
  2. Even if you have caught every possible injection possibility in your user interface, you cannot guarantee that every call to this API will be made only from your UI for all eternity. You may open up the API to the public or you may subcontract writing a mobile application that calls this API or you may hire a new programmer who doesn't know better.

The point is that you need to check security at every level of your application. And part of checking security is to not trust your inputs.

A far better approach than concatenating strings to form a SQL statement is to create parameter instances; set the value of each parameter; and add these parameters to a Parameters collection.

The code below shows how to do this.

string lastName = "Adams";
string sql = "Select * from dbo.Customer where LastName = @LastName";
string connString = ConfigurationManager.ConnectionStrings["LocalConn"].ConnectionString;
using (var conn = new SqlConnection(connString))
{
    conn.Open();
    var cmd = conn.CreateCommand();
    cmd.CommandText = sql;
    SqlParameter lnParam = cmd.CreateParameter();
    lnParam.ParameterName = "@LastName";
    lnParam.Value = lastName;
    cmd.Parameters.Add(lnParam);
    SqlDataReader reader = cmd.ExecuteReader();
    while (reader.Read())
    {
        Console.WriteLine("Good Name: {0} {1}", reader["FirstName"], reader["LastName"]);
    }
    Console.WriteLine();

Pass an unexpected parameter here and it will no t be executed on the end of the query because SQL Server is expecting a parameter for a specific use.

The same pattern works if I want to pass in a dynamic string of SQL. Passing Parameter instances is more secure than concatenating SQL and passing that string to SQL Server.

Below is a console application that uses the vulnerable string concatenation method to call SQL Server via ADO.NET

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

namespace PassingSql_WrongWay
{
    class Program
    {
        static void Main(string[] args)
        {
            CallSqlQuery();
            CallStoredProc();
            Console.ReadLine();
        }

        private static void CallSqlQuery()
        {
            string lastName = "'Adams'";
            //string lastName = "Adams';DROP TABLE dbo.ExtraTable;--";
            string sql = "Select * from dbo.Customer where LastName = '" + lastName + "'";
            string connString = ConfigurationManager.ConnectionStrings["LocalConn"].ConnectionString;
            using (var conn = new SqlConnection(connString))
            {
                conn.Open();
                var cmd = conn.CreateCommand();
                cmd.CommandText = sql;
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    Console.WriteLine("Bad Name: {0} {1}", reader["FirstName"], reader["LastName"]);
                }
            }
            Console.WriteLine();
        }

        private static void CallStoredProc()
        {
            string firstName = "James";
            string sql = "EXEC GetCustomersByFirstName '" + firstName + "'";
            string connString = ConfigurationManager.ConnectionStrings["LocalConn"].ConnectionString;
            using (var conn = new SqlConnection(connString))
            {
                conn.Open();
                var cmd = conn.CreateCommand();
                cmd.CommandText = sql;
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    Console.WriteLine("Bad Name: {0} {1}", reader["FirstName"], reader["LastName"]);
                }
                Console.WriteLine();
            }
        }
    }
}

Below is a similar console app, using the more secure parameters pattern

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

namespace PassingSql_RightWay
{
    class Program
    {
        static void Main(string[] args)
        {
            CallSqlQuery();
            CallStoredProc();
            Console.ReadLine();
        }

        private static void CallSqlQuery()
        {
            string lastName = "Adams";
            //string lastName = "Adams;DROP TABLE dbo.ExtraTable;--";
            string sql = "Select * from dbo.Customer where LastName = @LastName";
            string connString = ConfigurationManager.ConnectionStrings["LocalConn"].ConnectionString;
            using (var conn = new SqlConnection(connString))
            {
                conn.Open();
                var cmd = conn.CreateCommand();
                cmd.CommandText = sql;
                SqlParameter lnParam = cmd.CreateParameter();
                lnParam.ParameterName = "@LastName";
                lnParam.Value = lastName;
                cmd.Parameters.Add(lnParam);
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    Console.WriteLine("Good Name: {0} {1}", reader["FirstName"], reader["LastName"]);
                }
                Console.WriteLine();
            }
        }

        private static void CallStoredProc()
        {
            string firstName = "James";
            string storedProcName = "GetCustomersByFirstName";
            string connString = ConfigurationManager.ConnectionStrings["LocalConn"].ConnectionString;
            using (var conn = new SqlConnection(connString))
            {
                conn.Open();
                var cmd = conn.CreateCommand();
                cmd.CommandText = storedProcName;
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                SqlParameter lnParam = cmd.CreateParameter();
                lnParam.ParameterName = "@FirstName";
                lnParam.Value = firstName;
                cmd.Parameters.Add(lnParam);
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    Console.WriteLine("Good Name: {0} {1}", reader["FirstName"], reader["LastName"]);
                }
                Console.WriteLine();
            }
        }
    }
}

If you wish to use the above code, create a new database named TestData and run the following SQL DDL to create the database objects.

USE [TestData]
GO

/****** Object:  Table [dbo].[ExtraTable]    
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ExtraTable](
    [foo] [nchar](10) NULL,
    [bar] [nchar](10) NULL
) ON [PRIMARY]
GO

/****** Object:  Table [dbo].[Customer]    
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Customer](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [FirstName] [nvarchar](50) NULL,
    [LastName] [nvarchar](50) NOT NULL
) ON [PRIMARY]
GO

INSERT INTO dbo.Customer (FirstName, LastName) VALUES ('George', 'Washington') 
GO 
INSERT INTO dbo.Customer (FirstName, LastName) VALUES ('John', 'Adams') 
GO 
INSERT INTO dbo.Customer (FirstName, LastName) VALUES ('Thomas', 'Jefferson') 
GO 
INSERT INTO dbo.Customer (FirstName, LastName) VALUES ('James', 'Madison') 
GO 
INSERT INTO dbo.Customer (FirstName, LastName) VALUES ('James', 'Monroe') 
GO 
INSERT INTO dbo.Customer (FirstName, LastName) VALUES ('John Quincy', 'Adams') 
GO 

/****** Object:  StoredProcedure [dbo].[GetCustomersByFirstName]   
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetCustomersByFirstName]
    @FirstName NVARCHAR(50)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT 
            Id, 
            FirstName, 
            LastName
        FROM dbo.Customer
        WHERE FirstName = @FirstName
        ORDER BY Id
END
GO

With a little bit of thought and a few lines of code, you can significantly reduce the risk of SQL injection in your ADO.NET code.

.Net | C# | SQL Server
Friday, April 13, 2012 12:13:00 AM (GMT Daylight Time, UTC+01:00)
# Wednesday, April 11, 2012

As always, there will be a lot of developer conferences and other events this summer in the my region. Here is a partial list of conferences that have been announced in or near the Heartland region in the coming months. Please let me know if I have missed any.

What Where When
Kalamazoo X Kalamazoo, MI Apr 21
Stir Trek Columbus, OH May 4
Great Lakes Functional Programming Conference Ann Arbor, MI May 5
Cincinnati Day of Agile Westchester, OH May 19
Pittsburgh Tech Fest North Hills, PA Jun 9
CodeStock Knoxville, TN Jun 15-16
CloudDevelop Columbus, OH Aug 3
That Conference Wisconsin Dells, WI Aug 15-16
DevLink Chattanooga, TN Aug 29-31
Windows Azure Kick-Start Multiple cities Multiple dates
Windows 8 Developer Camps Multiple cities Multiple dates
Wednesday, April 11, 2012 3:37:00 PM (GMT Daylight Time, UTC+01:00)
# Monday, April 9, 2012
Monday, April 9, 2012 3:03:00 PM (GMT Daylight Time, UTC+01:00)
# Tuesday, April 3, 2012

Saturday, I spoke at the Orlando Code Camp at Seminole State College, just east of Orlando, FL. This was the seventh year of the Code Camp but my first time attending.

The first session I attended was Memory Management Fundamentals – Garbage Collection Deep Dive by Scott Dorman.
Scott explained the way memory management works under the hood.
Key points: 
The garbage collector takes care of cleaning up objects when they are no longer needed.
It's generally not advisable to implement a finalizer.
If your machine has plenty of memory, garbage collection might not occur until the user exits the app.
Larger objects are cued up for cleanup.
Here is a list of resources
http://geekswithblogs.net/sdorman/archive/2008/09/14/.net-memory-management-ndash-resources.aspx

The next session I attended was Creating a HTML5 WinRT application by Brian Kassay
You can build Windows 8 applications in either HTML5, JavaScript, and CSS3 or in XAML. This session focused on HTML5, JavaScript, and CSS3. In order to work with this, one needs to install Windows 8 and Visual Studio 11 (both are in beta).

I planned to see Richie Rump's Entity Framework - Code First and Magic Unicorns session, but others had the same idea and the room was packed. Rather than stand for an hour, I opted to hear Greg Leonardo's Line of Business development with MVC3.
This was a basic overview of how to use MVC. It consisted of more slides than demos.
He did explain how MVC's Anti-forgery library works (issues a token to the user with a response and checks for that token in subsequent requests).
He also discussed the MVC Anti-XSS library, which is designed to protect your site against cross-site scripting errors. By default, MVC disallows HTML input by. If you decide to allow HTML input, it is important to scrub input with the Anti-XSS library.

The final session I attended was Elijah Manor on Exterminating Those Common Pesky jQuery Bugs
Elijah went through a series of common JavaScript mistakes made by developers and showed ways to correct them.

I delivered a session on Visual Studio 2010 Database Tools. It was very well received and the audience asked lots of questions.

The conference was organized by local user group leaders, including Esteban Garcia, a fellow Telerik insider (Telerik sponsored my trip, BTW). The organizers did a very good job on this conference and everything ran smoothly.
The one drawback of this event was the lack of an obvious common area, where attendees could talk and meet one another. When it was over, we regrouped at a local pub, which gave me the opportunity to meet many of the local developer community. This was particularly important to me at this conference because I only knew about 5 people among the speakers and attendees. One of the reasons I came down to Orlando was for a chance to meet people in the local Florida communities. It turns out that Orlando, Sarasota, and South Florida have very vibrant communities based on the enthusiasm of those I spoke with.

Of course I recorded a couple episodes of Technology and Friends. Elijah Manor and Max Trinidad agreed to go on camera to discuss JavaScript and Powershell respectively.

The Orlando Code Camp will take place again next year and I'm seriously considering making this an annual trip. I also heard of a few smaller events in the area which might bring me back here.

Tuesday, April 3, 2012 3:46:00 PM (GMT Daylight Time, UTC+01:00)