Exercise 1: Connecting to a SQL Server DatabaseIn this exercise you will learn how connect to a SQL Server 2012 database from an ASP.NET application using ADO.NET, how to perform a simple query and how to display the results on a web page. This lab makes use of connection strings. If you are new to SQL Server, you should understand a few things about connection strings before we get started. Here is the connection string you will be using for this Hands-on Lab: XML The simple SQL Server connection string shown here has a three different attributes. Let’s examine each of them in more detail starting with Data Source. Normally the Data Source attribute is set to a string known as an instance, which in its simplest form is known as a default instance. A default instance simply specifies the name of the computer where SQL Server is installed, such as “MYSERVER”. You can also use “(local)” if the SQL Server resides on the same server as your application, a fully qualified domain name “myserver.mycompany.com”, or you can specify a TCP/IP address and port number. Sometimes it is useful to have multiple SQL Server installations on the same server. To accomplish this, SQL Server setup supports the ability to install a single default instance and additional named instances. A named instance takes the form “MYSERVER\MYINSTANCE”. You can find out the names of all of the SQL Server instances installed using the SQL Server Configuration Manager tool. In this lab, the Data Source is set to a server alias (‘SqlServerTrainingKitAlias’). A server alias provides a handy way to reference a SQL Server instance from multiple applications so it can be updated in one place without having to modify application source code. You create and edit a server alias using the SQL Server Configuration Manager tool. That wraps up our discussion of the Data Source attribute. The Integrated Security attribute tells ADO.NET what type of authentication to use to connect to SQL Server. When set to True, ADO.NET will attempt to use Windows Authentication to connect to SQL Server. Windows Authentication makes it easy to use existing security accounts defined in Windows or Active Directory instead of creating duplicate security accounts in the database. An added benefit is that you do not have to include security credentials in your connection string. In order to successfully connect to SQL Server using Windows Authentication, an administrator must have previously granted connection privileges to the Windows security account using the Transact-SQL CREATE LOGIN command or using a tool like SQL Server Management Studio. This is analogous to an administrator granting privileges to access other resources like a file, directory or share. SQL Server setup requires the user who is performing the installation to create a login for at least one Windows security account. Setup makes this login a member of the server-level sysadmin role. For this hands-on lab it is assumed that you installed SQL Server and therefore your Windows security account has connection and sysadmin privileges. Members of sysadmin can perform any activity on the SQL Server instance, so be careful! When the Integrated Security attribute is set to False, ADO.NET will attempt to use SQL Server Authentication to connect. SQL Server Authentication is useful when you do not have access to Windows or Active Directory security credentials, or if Windows Authentication is not supported in your environment. SQL Server Authentication must be enabled on the instance you are trying to connect to. It also requires that you specify two additional attributes in your connection string: “User ID” and “Password”. If you have to use SQL Server authentication, encrypt your connection strings to protect them. In order to successfully connect to SQL Server using SQL Server Authentication, an administrator must have previously granted connection privileges using the Transact-SQL CREATE LOGIN command or using a tool like SQL Server Management Studio. Here’s an example of a connection string that uses SQL Server authentication: XML
Note:
Best Practice: Use Windows Authentication to connect to SQL Server if your environment supports the use of Windows or Active Directory security credentials, otherwise use SQL Server authentication. If you use SQL Server Authentication, encrypt your connection strings to protect them.
Let us move on and talk about the Initial Catalog attribute. SQL Server not only supports multiple instances per server, but it also supports multiple databases per instance. This lab uses a database named “AdventureWorks2012”. Specifying an Initial Catalog in the connection string automatically switches the context of the current database when the application connects to ensure you are accessing the correct data, so it is important that you set it correctly to avoid making changes in the wrong database (like the master system database for example).
Note:
Best Practice: When constructing a connection string, always specify the Initial Catalog attribute to ensure your application is in the correct database context. Do not rely on default database settings.
Because each database may have different security and access requirements, SQL Server supports a robust security architecture based upon security principals. There are three layers of principals, Windows-level principals, SQL Server-level principals and database-level principals, and each of them can be secured separately. So far we have only dealt with access control for Windows-level and SQL Server-level principals. These principals will get you connected to SQL Server, but you will need to understand and properly configure database-level principals to actually work with data. The most common database-level principle is known as a database user. Database users are created in specific databases using the Transact-SQL CREATE USER command or a tool like SQL Server Management Studio. Each database user is associated with a server-level principal. In order to access or modify data, the database user performing the operation must have been granted privileges to do so using the Transact-SQL GRANT command or a tool like SQL Server Management Studio. Those privileges can be granted directly to the database user or to a database role that the database user is a member of. Examples of privileges include SELECT, UPDATE, INSERT, DELETE and EXECUTE (for running stored procedures). Note that some server-level principles, such as those that belong to the server-level sysadmin role, are automatically associated with a high-privileged database user known as dbo. This is a special user in all SQL Server databases known as the “database owner”. The database owner can perform all actions in a particular database because it is a member of the db_owner database-level role. Since this lab assumes your Windows security account is a member of sysadmin, we are also assuming you can access the AdventureWorks2012 database and perform operations in it as the database owner.
Note:
Best Practice: When accessing data in SQL Server, production applications should not use server-level principals that are members of the sysadmin server role (like sa), or database-level principles that are members of the db_owner role (like dbo). Designing a secure application requires the developer to employ the principle of least privilege. To implement this, create database roles that mirror the different types of users in your application, and grant only the privileges that are required to those roles.
Developers have the option of configuring their applications to connect to the database using the security credentials of the user, or alternatively using security credentials associated with the application (which in ASP.NET is known as an application identity). Using the user’s security credentials provides more flexibility in controlling access to data using built-in SQL Server functionality in an application-independent fashion, while using an application identity requires you to implement most data access control yourself in application logic, which is fine if only one application will access the data. One final note on connection strings. The format of connection strings can be unforgiving, and may vary from provider to provider. If you would like to construct your connection string using a higher-fidelity approach, check out the SqlServerConnectionStringBuilder class of ADO.NET. This wraps up our discussion of connection strings. Now it is time to start the hands-on lab! Task 1 − Connecting and Disconnecting from the SQL Server
In this exercise you will learn how to read data directly from SQL Server and display the results in an ASP.NET page. You will also learn how to execute a query that retrieves an image from the server and how to create a handler to display those images. Finally, you will learn how to page the items in SQL Server. Before we get started, this is a good time to introduce the concept of a database null value. If you are new to SQL Server and relational databases in general, you may be unfamiliar with how to correctly handle database null values. A database null value is represented using the NULL reserved word in Transact-SQL. In database terms, NULL means “unknown value”, and is not equivalent to anything including an empty string or a 0. You have to be careful when writing expressions in Transact-SQL that involve columns or variables that allow NULL values. NULL is not equal to anything else, even another NULL value. This is the default behavior of SQL Server. The expression “MyColumn = NULL” will always evaluate to false, regardless of whether there are NULL values in MyColumn or not.
Note:
Best Practice: When designing your application, do not change the default SQL Server behavior for how expressions that involve NULLs are evaluated. While this is currently supported in SQL Server 2012 by disabling the ANSI_NULLS query option, the ability to do so will be deprecated in a future release.
The correct syntax to test for a NULL value in Transact-SQL is to use the “IS NULL” or “IS NOT NULL” clause. For example: “MyColumn IS NULL” or “MyColumn IS NOT NULL”. Transact-SQL also provides a handy ISNULL function, which automatically replaces a NULL with a different value. For example: Transact-SQL The execution of the previous Transact-SQL command returns the string “empty” for any rows where MyColumn is NULL. This can be useful when you want to avoid handling database null values in an application.
Note:
Best Practice: When designing queries, always be aware of whether the columns accessed by your application allow null values and handle them correctly in your application source code when constructing Transact-SQL commands and processing results.
Let us move on and talk about how to implement this best practice in the .NET Framework. The .NET Framework uses DbNull.Value in System.Data to represent a database null value. DBNull.Value can only be used to assign a database null value to a database column or parameter. For example, you can set the SqlParameter.Value property to DBNull.Value, but you cannot set the value of a string variable to DBNull.Value. The .NET Framework supports the concept of a nullable type which can be useful when dealing with database nulls in an application. A type is considered nullable if it supports a null reference. Reference type variables, such as a variable designed to work with an instance of a class, point to a location in memory where the data is located. If an instance of the class has not been created yet, the variable is said to have a null reference. In .NET terms, a null reference means “points to nothing”, and is equivalent to another null reference, but not to anything else including 0, an empty string or DBNull.Value. One of the most commonly used nullable reference types is System.String for working with Unicode strings. This means that strings are treated as an instance of a class in the .NET Framework, not as a primitive value type like an Integer or Boolean. You can write expressions using the null keyword in C# (or Nothing in Visual Basic) to test for a null reference or to initialize a class variable to a null reference. For example, the C# statement “string myString = null;” declares a variable of type System.String that points to nothing. At this point the C# expression “myString == null” evaluates to true. Some applications use the concept of a null reference to imply a database null value. This is a perfectly acceptable approach as long as you understand three inconsistencies between the .NET concept of a null reference and the SQL Server concept of a database null value.
As long as you are aware of these inconsistencies, you can avoid logic errors in your application when using a null reference to imply a database null value. Now that you understand the basics of how to handle database null values using nullable types, let us move on. |