Thursday, September 3, 2009

pagging in datalist....

using System;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Gallery_sports : System.Web.UI.Page
{

static int trow = 0, cindx, pgsize;
ADOC fm = new ADOC();

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
pgsize = 9;
cindx = 0;
imageload();
}
}

private void imageload()
{
try
{
if (!string.IsNullOrEmpty(Session["Imgtyp"].ToString()))
{

if (Session["Imgtyp"].ToString() == "InterSchool")
{
load_image("Inter_school");
this.Label1.Text = "Inter School Competion";
}
else if (Session["Imgtyp"].ToString() == "Saraswati")
{
load_image("saraswati_pooja");
this.Label1.Text = "Saraawati Pooja";
}

else if (Session["Imgtyp"].ToString() == "Sports")
{

load_image("Sports");
this.Label1.Text = "Sports";
}
else if (Session["Imgtyp"].ToString() == "IntraSchool")
{

load_image("Intra_school");
this.Label1.Text = "Intra School Competion";
}
else if (Session["Imgtyp"].ToString() == "Bosco_evergreen")
{

load_image("Bosco_evergreen");
this.Label1.Text = "Bosco Evergreen";
}
}
}

catch
{ load_image("Sports"); }
}

#region"------------LoadImage-----------------"



private void load_image(string strpt)
{
SqlConnection objConn = new SqlConnection(ConfigurationManager.AppSettings["strConn"]);
SqlDataAdapter objDA = new SqlDataAdapter("exec sp_Photo_gallery '','"+strpt+"','','','',4,''", objConn);
DataSet objDS = new DataSet();

if (!Page.IsPostBack)
{
objDA.Fill(objDS);
trow = objDS.Tables[0].Rows.Count;
objDS = null;
objDS = new DataSet();
}

objDA.Fill(objDS, cindx, pgsize, "Photo_gallery");
this.dList.DataSource = objDS.Tables[0].DefaultView;
this.dList.DataBind();
objConn.Close();


}

public void ShowNext(object s, EventArgs e)
{
if (cindx + 1 <>
{
cindx = cindx + pgsize;
}

imageload();
}

public void ShowPrevious(object s, EventArgs e)
{
cindx = cindx - pgsize;
if (cindx <>
{
cindx = 0;
}

imageload();
}

# region"============DataList Page Status Check ================"

private void DataList_Status(int cindx, int pgsize, int trow, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Footer)
{
Label lbl = (Label)e.Item.FindControl("lblStatus");

lbl.Text = "";
lbl.Text = "Total Records:" + trow;
lbl.Text += " - Showing Page: ";
lbl.Text += Convert.ToInt32((cindx / pgsize) + 1).ToString();
lbl.Text += " of ";

Button btn_nxt = (Button)e.Item.FindControl("Button1");
if ((trow % pgsize) > 0)
{
lbl.Text += Convert.ToInt32((trow / pgsize) + 1).ToString();
if (Convert.ToInt32((cindx / pgsize) + 1).ToString() == Convert.ToInt32((trow / pgsize) + 1).ToString())
{

btn_nxt.Enabled = false;
}

}
else
{
lbl.Text += Convert.ToInt32(trow / pgsize).ToString();
if (Convert.ToInt32((cindx / pgsize) + 1).ToString() == Convert.ToInt32((trow / pgsize)).ToString())
{

btn_nxt.Enabled = false;
}
}
lbl.Text += "";


Button btn_prv = (Button)e.Item.FindControl("Button2");
if ((cindx + 1) == 1)
{

btn_prv.Enabled = false;
}
else
{
btn_prv.Enabled = true;
}
}
}

#endregion


#endregion

protected void Button1_Click(object sender, EventArgs e)
{
ShowNext(sender, e);
}

protected void Button2_Click(object sender, EventArgs e)
{
ShowPrevious(sender, e);
}

protected void dlImages_ItemCreated(object sender, DataListItemEventArgs e)
{
DataList_Status(cindx, pgsize, trow, e);
}
}

Mail Sending Code....

This summary is not available. Please click here to view the post.

Monday, August 17, 2009

ASP.NET Page Lifecycle

Introduction

Understanding Page lifecycle is very crucial in order to develop ASP.NET applications. Most beginners tend to get confused while dealing with dynamic controls and face problems like losing values, state etc on postbacks. Since HTTP is stateless, the nature of web programming is inherently different from windows application development, and the Page lifecycle is one of the primary building blocks while learning ASP.NET. The sequence of events, especially while working with MasterPages in ASP.NET 2.0, has become slightly more complex and this article is aims to shed some light on these events by explaining the order and importance of each event.

Background

Whenever the user requests a particular .aspx page in an application, a lot of interesting things happen on the web server where the application is hosted. Understanding this sequence of events will help us to program and respond to events properly and also clear any confusion which generally arises due to the stateless nature of web programming.

Basics: The New Compilation Model and the Partial Classes

Each web form in an ASP.NET application derives directly or indirectly from a System.Web.UI.Page class. A web form has two components: a code behind file (WebForm.aspx.cs) which contains the code for the events and other methods related to a Page, and the designer ASPX file, which contains HTML control declarations and events (in the Visual Studio 2005 Web Application project model, we have a designer class named WebForm.aspx.designer.cs).

In ASP.NET 2.0, we do not need to define the control variables as well as there event handlers in the code behind, thanks to Partial classes. In ASP.NET 1.x, all this code was auto generated and placed in the code behind file under InitializeComponent() section. But in version 2.0, the runtime will create a partial class dynamically from the ASPX page containing all this info and merge it with the code behind partial class. This will help in making the actual code behind class a lot cleaner and more manageable.

Also, this would eliminate the name change related issues which were common in VS 2003 (if we change any control's ID, it had to be changed everywhere and VS used to modify the code many times). All control related events are defined in the ASPX markup code. So having a single place for controls names and event handlers is cleaner and flexible, whereas the previous VS 2003 model was more "brittle".

Real Thing: The Page life cycle

It is very important to know that for each request, the Page class is instantiated everytime from “scratch”. Which means that any values or whatever state it had previously will get lost unless we use one of the various state maintainance mechanisms provided by ASP.NET like Application, Session, Cache variables or Cookies.

Side Note: View state in ASP.NET 2.0 has changed and now comprises of two parts: Control State and View state. Refer this article for details:

http://msdn2.microsoft.com/en-us/library/1whwt1k7%28VS.80%29.aspx

Below is the sequence of events which fire up sequentially with explanation on the relative importance with respect to web programming in code behind:

Important Note: All events except the Init() and Unload() are fired from outermost to the innermost control. For e.g., a user control’s init event would fire before the Page_Init() event of its parent Page class.

1. PreInit()

In this Page level event, all controls created during design time are initialized with their default values. For e.g., if you have a TextBox control with Text property = “Hello”, it would be set by now. We can create dynamic controls here.

This event occurs only for the Page class and UserControls/MasterPages do not have this method to override.

Sample code where you can override this method and add your custom code:

protected override void OnPreInit(EventArgs e)

{
//custom code

base.OnPreInit(e);
}


Note that PreInit() is the only event where we can set themes programmatically.

Special Case with MasterPages

It is important to note that Master Page is treated like a control in the Content Pages.
So if a Page has a Master Page associated with it, then the controls on the page will not be initialized and would be null in this stage. Only after the Init() event starts, you can access these controls directly from the page class. Why?

The reason being that all controls placed in the Content Page are within a ContentPlaceholder which is a child control of a MasterPage. Now Master Page is merged and treated like a control in the Content Pages. As I mentioned earlier, all events except the Init() and Unload() are fired from outermost to the innermost control. So PreInit() in the Page is the first event to fire but User Controls or MasterPage (which is itself a Usercontrol) do not have any PreInit event . Therefore in the Page_PreInit() method, neither the MasterPage nor any user control has been initialized and only the controls inside the Page class are set to their default values. Only after the Page_PreInit() event the Init() events of other controls fire up.

See the diagram below showing control hierarchy after the Page_Init() event:



2. OnInit()

In this event, we can read the controls properties (set at design time). We cannot read control values changed by the user because that changed value will get loaded after LoadPostData() event fires. But we can access control values from the forms POST data as:

string selectedValue = Request.Form[controlID].ToString();

3. LoadViewState

This will only fire if the Page has posted back (IsPostBack == true). Here the runtime de-serializes the view state data from the hidden form element and loads all controls who have view state enabled.

4. LoadPostBackData

Again, this method will only fire if the Page has posted back.
In this event the controls which implement IPostBackDataHandler interface gets loaded by the values from the HTTP POST data. Note that a textbox control does not gets its value from the view state but from the post data in the form in this event. So even if you disable view state for a particular control, it can get its value from the HTTP POST data if it implements IPostBackDataHandler interface.

Also, an important point to note is that if we have a DropDownList control and we have dynamically added some items to it, the runtime cannot load those values unless the view state is enabled (even if the control derives from IPostBackDataHandler). The reason being that HTTP Post data has only one value per control, and the entire value collection is not maintained in the PostData but in view state.

5. Page_Load

This is the most popular method and the first one for all beginner developers to put their code. Beginners may also think that this is the first method which fires for a Page class. This can lead to a lot of confusion which makes understanding the Page lifecycle all the more important.

Note: If the page has any user control, then it's Load method will fire after the Page class's Load method. The reason as explained earlier is the fact that all method except the Init() are fired from the outermost control to the innermost. So after Page_Load(), load methods of all other controls are fired recursively.

6. Control Event Handlers

These are basically event handlers (like Button1_Click()) which are defined for controls in the ASPX markup. Another source of confusion arises when the developer thinks that an event handler like Button_Click() should fire independently (like in windows apps) as soon as he clicks a Button on the web form, forgetting that Page_Load will fire first before any event handlers.

7. PreRender

This event is again recursively fired for each child controls in the Page. If we want to make any changes to control values, this is the last event we have to peform the same.

8. SaveViewState
Here, the ViewState of the controls gets saved in the form's hidden control.

9. Render

In this method all controls are rendered recursively (i.e. Render method of each control is called).

10. Unload

Here you can have the page and controls perform clean-up operations. This event has no relevance besides clean up operations because the Page has already rendered.

Dynamic Controls

Now we have seen the important events in the Page lifecycle, let's focus on how to create and maintain state of dynamically generated controls. Many times we need to generate controls dynamically for specific business use cases. For example, I was managing a famous hotel reservation website project and one of my team members was facing an issue in handling the Reservation screen. There was a TextBox where the user enters the number of
rooms, and based on that value, dynamic usercontrols having a room's detailed info were created at runtime.

The developer complained that although he was able to generate user controls as runtime in a for loop, but was unable to save their state. When I looked into the code, I noticed that the code to generate controls was written in a Button's Click event handler. Now as we dicussed above, event handlers like Button_Click() fire much later than LoadViewState() and LoadPostData(), where the control values get loaded from the view state and form's Post data.

So unless he recreates the controls in the Page_Init() or Pre_Init() methods (which occur before LoadViewState and LoadPostData), the control values modified by the user won't get reloaded next time.

Now, when he put the code in the Page_Init() event, he was unable to get the number of rooms entered by the user in the TextBox (which was a static control). The reason being that in Page_Init(), control values are initilized to their design time default values, and do not reflect the user entered values unless they are loaded from the POST data or the view state, a process which occurs later.

So the only way to access the user entered value in the control is to get the value from the form's POST data. Here is the code:


protected override void OnInit(EventArgs e)

{
//get value of the TextBox from HTTP POST data

string selectedValue ;
if(Request.Form["txtNoOfRooms"] != null)

selectedValue = Request.Form["txtNoOfRooms"].ToString();


//code to create controls dynamically...

...............


base.OnInit(e);
}


Note: Thanks to Mike Banavige of ASP.NET forums, I added this section. If you create a dynamic control in the Page_Load event, and add it to a PlaceHolder or Panel (with view state turned on), then this dynamic control will maintain its state even though it was not created in the Page_Init(). Why?

The reason is the fact that once a control is added to the control tree of the page, TrackViewState() method is responsible for tracking the state. This method gets fired automatically whenever the control is added to the control tree. Due to this reason, any modifications to the control (like adding items etc) should be done *only after* the dynamic control has been added to the control tree of the Page class, else the state would be lost. See the code below:

protected void Page_Load(object sender, EventArgs e)
{
//create a dynamic dropdown


DropDownList d = new DropDownList();

PlaceHolder1.Controls.Add(d); // TrackViewState() gets fired for our dropdown, so state is maintained


if (!IsPostBack)

{

d.Items.Add("test1");
d.Items.Add("test2");

}

}

This will not work:

protected void Page_Load(object sender, EventArgs e) 

{

//create a dynamic dropdown

DropDownList d = new DropDownList();

if (!IsPostBack)

{

d.Items.Add("test1");

d.Items.Add("test2");

}

PlaceHolder1.Controls.Add(d); //"test1" and "test2" values are lost

}

Summary

I have tried to explain relevant events in the Page lifecycle and their importance with some gotchas. I will keep updating this article with more tips and tricks, besides readers are welcome to point out mistakes and suggest corrections and give feedback!

An important thing to remember here is that the entire lifecycle is repeated on every request. The Page class gets re-instantiated and after serving the request gets unloaded. Once we are clear with the sequence of the events, we can structure our code well to suit different use case requirements.

Saturday, July 25, 2009

Explains Authentication Techniques

Well, as you all are familiar what authentication is and what ASP .NET is, I will directly jump to the different types of ASP .NET Authentication options we have.

The three main types of authentication available in ASP .NET are:
1) Windows Authentication
2) Forms Authentication
3) Passport Authentication
The authentication process can be divided into following steps. Reading this will give you a more clear idea and helps understanding this article.
STEPS
1) The request is first served by IIS server. IIS check for the IP of incoming request and allow or deny access according to the allowable domain access configuration.
2) Next thing is IIS will perform it’s authentication it is configured to do. By default it allows all access but you can always go back and change it per application.
3) Once this is done request is passed to ASP .NET application itself where the authentication of the user is performed according to the setting made in WEB.CONFIG and further the resources are allowed or denied to the user.
Now remember our three authentication techniques I described at start.
1) Windows Authentication: will allow you to authenticate user on his/her windows account and credentials. IIS does this for you and passes and credential to code page if required. This is used when the application is an INTRANET application and uses are fixed.
2) Passport Authentication: uses Microsoft passport services to authenticate user. This is used when you have different application hosed on a server and you want to provide single time authentication to user. What I mean is once he/she is authenticated he/she will be authorized to access other applications without any authentication process which has passport authentication as its authentication method.
3) Forms Authentication: This is the most commonly used method of authentication. Simple THML forms are used to collect user data and they are validated against your database and custom configuration for specific user.
Before we go ahead and see details of these methods go through the diagram below. It will give you more idea about I mentioned above.


Now let’s start with each of the above methodology to perform ASP .NET authentication. Let’s take a look at passport authentication and windows authentication first.
1) Passport Authentication
This lets you integrate your application with Microsoft Passport services to authenticate users and allow access to your application resources. This has a major benefit named single-sign on. It means user has to provide credentials only once to access all the application using passport authorization.
It uses encrypted cookie mechanism. To use and implement this in your application you have to download Passport Software Development kit and it has to be installed on your server where you are going to host your application. Sample implementation is shown as below.
<configuration>
<authenticationmode="Passport">
<passportredirectUrl="login.aspx" />
authentication>
<authorization>
<deny users="?" />
authorization>
configuration>
2) Windows Authentication
As I have mentioned before while creating Intranet application the first choice comes to our mind is windows authentication mode. When you integrate windows authentication you don’t have to create login page and maintain username/password database. But yes if you want to customize application to your get windows authentication and custom mode you need to manage table where you have to define user roles with your with their domain username in database.
This can be implemented as simply as writing following lines in your web.config file.
<authenticationmode="Windows" />
<authorization>
<denyusers="?"/>
authorization>
The benefit of using “Deny users” is that application is only available when username is always available from code on the server. I remember creating an application for one of my project where I had to implement mix-mode authentication along with windows authentication. I had to create different roles according to organization’s requirement and then allow/deny resources to the users according to their domain login name. If you have any question regarding this kind of mix mode authentication please send me an email and I would be more than happy to help you with your custom requirements.
I will try to briefly incorporate this. Simply create a table where the actual user names (Domain) user names are store. Let’s say your login name is “k.smith” in your company domain, store this in your database and store user role against this username. Again user roles can be complex and possibly a combination of 2-3 tables.
Once you store this in your database you can always check at the page load time the user from whom the request is coming from. That can be achieved from code below.
System.Security.Principal.IPrincipal User;
User = System.Web.HttpContext.Current.User;
string username = User.Identity.Name;
Now you have user name so you can check the role associated with this username and show/hide menu items accordingly. That’s it for now. I will explain more about Forms authentication in second part of this article.

Wednesday, July 22, 2009

javascript


N-Tier Web Applications using ASP.NET 2.0 and SQL Server 2005 - Part 1

When .NET Framework was first introduced, it provided excellent features that made the construction of ASP.NET applications a breezy experience. Now the next version of .NET Framework (version 2.0) along with SQL Server 2005 builds on the foundation of the previous versions and introduces some new features that can greatly aid in the design and development of N-Tier ASP.NET 2.0 applications. In this article, I will show you to how to construct an N-Tier ASP.NET 2.0 Web application by leveraging the new features of ASP.NET 2.0 and SQL Server 2005 such as TableAdapter Configuration Wizard, ObjectDataSource Control, App_Code directory to store reusable components, Master Pages, CLR Stored Procedures, and Caching. Along the way, I will also highlight the best practices of using the new ASP.NET features for building N-Tier enterprise class Web applications. From an implementation standpoint, Part-1 of this article will focus on the creation of CLR stored procedures and the data access components in addition to describing the overall architecture of the sample application. Part-2 will focus on the business logic layer object, ASP.NET user interface pages, caching and so on.

Introduction
Designing N-Tier client/server architecture is no less complex than developing two-tier architecture, however the N-Tier architecture, produces a far more flexible and scalable client/server environment. In two-tier architecture, the client and the server are the only layers. In this model, both the presentation layer and the middle layer are handled by the client. N-Tier architecture has a presentation layer and three separate layers - a business logic layer and a data access logic layer and a database layer. The next section discusses each of these layers in detail.

Different Layers of an N-Tier application

In a typical N-Tier environment, the client implements the presentation logic (thin client). The business logic and data access logic are implemented on an application server(s) and the data resides on database server(s). N-tier architecture is typically thus defined by the following layers:

Presentation Layer: This is a front-end component, which is responsible for providing portable presentation logic. Since the client is freed of application layer tasks, which eliminates the need for powerful client technology. The presentation logic layer consists of standard ASP.NET web forms, ASP pages, documents, and Windows Forms, etc. This layer works with the results/output of the business logic layer and transforms the results into something usable and readable by the end user.
Business Logic Layer: Allows users to share and control business logic by isolating it from the other layers of the application. The business layer functions between the presentation layer and data access logic layers, sending the client's data requests to the database layer through the data access layer.
Data Access Logic Layer: Provides access to the database by executing a set of SQL statements or stored procedures. This is where you will write generic methods to interface with your data. For example, you will write a method for creating and opening a SqlConnection object, create a SqlCommand object for executing a stored procedure, etc. As the name suggests, the data access logic layer contains no business rules or data manipulation/transformation logic. It is merely a reusable interface to the database.
Database Layer: Made up of a RDBMS database component such as SQL Server that provides the mechanism to store and retrieve data.
Now that you have a general understanding of the different layers in a N-Tier application, let us move onto discuss the implementation of a N-Tier Web application.

Implementation
In this article, I will consider an example web site (that displays authors and author titles information) constructed using N-Tier principles and use the example Web site to demonstrate the new features of ASP.NET 2.0 and SQL Server 2005. The sample Web site shown in this example is very simple and straightforward and will consist of only two pages: the first page will show the list of authors from the pubs database and the second page will display the list of titles specific to a selected author.

Please note that this article is not aimed at providing an exhaustive coverage of the individual features of ASP.NET 2.0, instead it only focuses on helping the readers understand the features of ASP.NET 2.0 and SQL Server 2005 that are essential to building a N-Tier web application.

Architecture of the Example Application
The following screenshot shows the different layers in the example application. It also highlights the important characteristics of the example application.
Some of the important characteristics of the sample application are as follows:

1.The stored procedures in the SQL Server 2005 database are created using C#. The ability to create stored procedures in managed code enables complex business logic to be executed close to the database resulting in performance improvements. The compiled nature of the stored procedure also results in increased performance.
2.The data access layer classes are generated using the new TableAdapter Configuration Wizard, which enables you to create data access layer classes without writing a single line of code.
3.ASP.NET Web forms in the user interface layer are generated using master pages, providing a consistent look and feel for the entire application.
4.Web forms utilize ObjectDataSource control to directly bind the output of the middle tier methods to data bound controls such as a GridView control.
5.Web forms also take advantage of caching of database contents to increase the performance and throughput of the web application. This is made possible by the use of the database cache invalidation mechanism that can automatically remove specific items from the cache when the data in the database table changes.

Implementation of the Application


I will discuss the implementation by discussing each of the above layers, starting with the database layer.

Database Objects using Managed Code

One of the neat features of SQL Server 2005 is the integration with the .NET CLR. The integration of CLR with SQL Server extends the capability of SQL Server in several important ways. This integration enables developers to create database objects such as stored procedures, user defined functions, and triggers by using modern object-oriented languages such as VB.NET and C#. In this article, I will demonstrate how to create the stored procedures using C#. Before looking at the code, let us understand the pros and cons of using managed language in the database tier to create server side objects.

T-SQL Vs Managed Code

Although T-SQL, the existing data access and manipulation language, is well suited for set-oriented data access operations, it also has limitations. It was designed more than a decade ago and it is a procedural language rather than an object-oriented language. The integration of the .NET CLR with SQL Server enables the development of stored procedures, user-defined functions, triggers, aggregates, and user-defined types using any of the .NET languages. This is enabled by the fact that the SQL Server engine hosts the CLR in-process. All managed code that executes in the server runs within the confines of the CLR. The managed code accesses the database using ADO.NET in conjunction with the new SQL Server Data Provider. Both Visual Basic .NET and C# are modern programming languages offering full support for arrays, structured exception handling, and collections. Developers can leverage CLR integration to write code that has more complex logic and is more suited for computation tasks using languages such as Visual Basic .NET and C#. Managed code is better suited than Transact-SQL for number crunching and complicated execution logic, and features extensive support for many complex tasks, including string handling and regular expressions. T-SQL is a better candidate in situations where the code will mostly perform data access with little or no procedural logic. Even though the example you are going to see in this article is best written using T-SQL, I will take the managed code approach and show you how to leverage that feature.

Creating CLR Based Stored Procedures

For the purposes of this example, create a new SQL Server Project using Visual C# as the language of choice in Visual Studio 2005. Since you are creating a database project, you need to associate a data source with the project. At the time of creating the project, Visual Studio will automatically prompt you to either select an existing database reference or add a new database reference. Choose pubs as the database. Once the project is created, select Add Stored Procedure from the Project menu. In the Add New Item dialog box, enter Authors.cs and click Add button. After the class is created, modify the code in the class to look like the following.

using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public class Authors
{
[SqlProcedure]
public static void GetAuthors()
{
SqlPipe sp = SqlContext.Pipe;
using (SqlConnection conn = new
SqlConnection("context connection=true"))
{
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
cmd.CommandText = "Select DatePart(second, GetDate()) " +
" As timestamp,* from authors";
SqlDataReader rdr = cmd.ExecuteReader();
sp.Send(rdr);
}
}

[SqlProcedure]
public static void GetTitlesByAuthor(string authorID)
{
string sql = "select T.title, T.price, T.type, " +
"T.pubdate from authors A" +
" inner join titleauthor TA on A.au_id = TA.au_id " +
" inner join titles T on TA.title_id = T.title_id " +
" where A.au_id = '" + @authorID + "'";
using (SqlConnection conn = new
SqlConnection("context connection=true"))
{
conn.Open();
SqlPipe sp = SqlContext.Pipe;
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
cmd.CommandText = sql;
SqlParameter paramauthorID = new
SqlParameter("@authorID", SqlDbType.VarChar, 11);
paramauthorID.Direction = ParameterDirection.Input;
paramauthorID.Value = authorID;
cmd.Parameters.Add(paramauthorID);
SqlDataReader rdr = cmd.ExecuteReader();
sp.Send(rdr);
}
}
}
Let us examine the above lines of code. The above code starts by importing the required namespaces and then declares a class named Authors. There are two important classes in the Microsoft.SqlServer.Server namespace that are specific to the in-proc provider:

***SqlContext: This class encapsulates the extensions required to execute in-process code in SQL Server 2005. In addition it provides the transaction and database connection which are part of the environment in which the routine executes.
***SqlPipe: This class enables routines to send tabular results and messages to the client. This class is conceptually similar to the Response class found in ASP.NET in that it can be used to send messages to the callers.

The Authors class contains two static methods named GetAuthors and GetTitlesByAuthor. As the name suggests, the GetAuthors method simply returns all the authors from the authors table in the pubs database and the GetTitlesByAuthor method returns all the titles for a specific author.

Inside the GetAuthors method, you start by getting reference to the SqlPipe object by invoking the Pipe property of the SqlContext class.

SqlPipe sp = SqlContext.Pipe;

Then you open the connection to the database using the SqlConnection object. Note that the connection string passed to the constructor of the SqlConnection object is set to "context connection=true" meaning that you want to use the context of the logged on user to open the connection to the database.

using (SqlConnection conn = new SqlConnection("context connection=true"))

Here open the connection to the database using the Open() method.

conn.Open();

Then you create an instance of the SqlCommand object and set its properties appropriately.

SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
cmd.CommandText = "Select DatePart(second, GetDate()) " + " As timestamp,* from authors";

Finally you execute the sql query by calling the ExecuteReader method of the SqlCommand object.

SqlDataReader rdr = cmd.ExecuteReader();

Then using the SqlPipe object, you then return tabular results and messages to the client. This is accomplished using the Send method of the SqlPipe class.

sp.Send(rdr);

The Send method provides various overloads that are useful in transmitting data through the pipe to the calling application. Various overloads of the Send method are:

*Send (ISqlDataReader) - Sends the tabular results in the form of a SqlDataReader object.
*Send (ISqlDataRecord) - Sends the results in the form of a SqlDataRecord object.
*Send (ISqlError) - Sends error information in the form of a SqlError object.
*Send (String) - Sends messages in the form of a string value to the calling application.

Both the methods in the Authors class utilize one of the Send methods that allows you to send tabular results to the client application in the form of a SqlDataReader object. Since the
GetTitlesByAuthor method implementation is very similar to the GetAuthors method, I will not be discussing that method in detail.

Now that the stored procedures are created, deploying it is very simple and straightforward. Before deploying it, you need to build the project first. To build the project, select Build->Build from the menu. This will compile all the classes in the project and if there are any compilation errors, they will be displayed in the Error List pane. Once the project is built, you can then deploy it onto the SQL Server by selecting Build->Deploy from the menu. This will not only register the assembly in the SQL Server but also deploy the stored procedures in the SQL Server. Once the stored procedures are deployed to the SQL Server, they can then be invoked from the data access layer, which is the topic of focus in the next section.

Before executing the stored procedure, ensure you execute the following sql script using SQL Server Management Studio to enable managed code execution in the SQL Server.

EXEC sp_configure 'clr enabled', 1;
RECONFIGURE WITH OVERRIDE;
GO

Data Access Layer using TableAdapter Configuration Wizard

Traditionally the process you employ to create data access layer classes is a manual process, meaning that you first create a class and then add the appropriate methods to it. With the introduction of Visual Studio 2005, Microsoft has introduced a new TableAdapter Configuration Wizard that makes creating a data access logic layer class a breezy experience. Using this wizard, you can create a data access logic layer component without having to write a single line of code. This increases the productivity of the developers to a great extent. Once you create those classes, you can consume them exactly the same way you consume built-in objects. Before looking at an example, let us briefly review what a TableAdapter is. A TableAdapter connects to a database, executes queries, or stored procedures against a database, and fills a DataTable with the data returned by the query or stored procedure. In addition to filling existing data tables with data, TableAdapters can return new data tables filled with data. The TableAdapter Configuration Wizard allows you to create and edit TableAdapters in strongly typed datasets. The wizard creates TableAdapters based on SQL statements or existing stored procedures in the database. Through the wizard, you can also create new stored procedures in the database.

This section will discuss the creation of a data access component that will leverage the stored procedures created in the previous step. To start, create a new ASP.NET web site named NTierExample in Visual C# by selecting New Web Site from the File menu as shown below.

To create a data component, begin by right clicking on the web site and selecting Add New Item from the context menu. In the Add New Item dialog box, select DataSet from the list of templates. Change the name of the file to Authors.xsd and click Add.

When you click Add, you will be prompted if you want to place the component inside the App_Code directory. Click OK in the prompt and this will bring up the TableAdapter Configuration Wizard. In the first step of the TableAdapter Configuration Wizard, you need to specify the connection string and in the second step you will be prompted if you want to save the connection string in the web.config file. In this step, save the connection string to the web.config file by checking the check box.

In the next step, you will be asked to choose a command type. Select the Use existing stored procedures option as shown below and click Next.

Clicking Next in the above screen brings up the following screen wherein you select the stored procedure to use.


Click Next in the above dialog box and you will see the Choose Methods to Generate dialog box wherein you can specify the name of the method that will be used to invoke the stored procedure selected in the previous step. Specify the name of the method as GetAuthors as shown below:

Clicking Next in the above screenshot results in the following screen wherein you just hit Finish.
When you click on Finish, Visual Studio will create the required classes for you. After the classes are created, you need to rename the class to Authors. After making all the changes, the final output should look as follows.

That's all there is to creating a data access component using the TableAdapter Configuration Wizard. As you can see, all you have to do is to provide the wizard with certain information and Visual Studio hides all the complexities of creating the underlying code for you.


Now that you have created the data access layer method for the GetAuthors stored procedure, you need to do the same thing for the GetTitlesByAuthor stored procedure. To this end, add another TableAdapter to the Authors.xsd by selecting Data->Add->TableAdapter from the menu and follow through the wizard steps. Remember to specify the stored procedure name as GetTitlesByAuthor this time. Note that at the time of writing this article using Visual Studio 2005 Beta 2, I encountered some problems in getting the wizard to work because of some bugs. If you run into any problem with the wizard, simply exit from the wizard, select the appropriate TableAdapter from the designer and select View->Properties Window from the menu. Through the properties dialog box, you should be able to perform all the configurations related to a TableAdapter.


Storing Utility Classes in App_Code Directory

You might remember that when you created the data component, you placed the data component class inside the App_Code directory, which is a special directory used by ASP.NET. It is very similar to bin directory, but with the following exceptions: While the bin directory is designed for storing pre-compiled assemblies used by your application, the App_Code directory is designed for storing class files to be compiled dynamically at run time. This allows you to store classes for business logic components, data access components, and so on in a single location in your application, and use them from any page. Because the classes are compiled dynamically at run time and automatically referenced by the application containing the App_Code directory, you don't need to build the project before deploying it, nor do you need to explicitly add a reference to the class. ASP.NET monitors the App_Code directory and when new components are added, it dynamically compiles them. This enables you to easily make changes to a component and deploy with a simple XCOPY or with a drag-and-drop operation. In addition to simplifying the deployment and referencing of components, the \App_Code directory also greatly simplifies the creation and accessing of resource files (.resx) used in localization, as well as automatically generating and compiling proxy classes for WSDL files (.wsdl).


With the introduction of this new directory, you might be wondering when to use this directory when compared to the bin directory. If you have an assembly that you want to use in your web site, create a bin subdirectory and then copy the .dll to that subdirectory. If you are creating reusable components that you want to use only from your ASP.NET pages, place them under the App_Code directory. Note that any class you add to the App_Code directory is visible only within that Web site meaning that it will not be visible outside of that Web site. So if you are creating a class that needs to be shared across multiple Web sites, you will be better off creating that class as part of a class library project and share that project among those Web sites.


Conclusion

In this installment, you have understood the new features of SQL Server 2005 utilized to create stored procedures using managed language such as C#. After that, you have also seen the steps involved in creating the data access components using TableAdapter Configuration Wizard that greatly simplified the process of creating a data access component. In Part-2 of this article, we will see how to consume this data access components from a business logic layer. We will also look at the use of master pages in creating the user interface, and caching features in ASP.NET 2.0 and so on.