-7-

 

CGI Programming

 

This chapter concentrates on the basics of the Internet. By the time you reach the end of this chapter, you will be comprehensibly conversant with the role of a web server, a web browser and ASP.Net. You will also be in a position to appreciate the indispensability of ASP.Net, in writing powerful business applications.

 

Understanding the samples provided by Microsoft, is akin to viewing ASP from a height of 10000 miles.

 

At the outset, you are required to create a file called a.cs in the sub-directory c:\inetpub\scripts. We will explain the relevance of this subdirectory in due course of time.

 

a.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("<b>hi");

}

}

 

The above is a short and sweet C# program! Now, compile this program using the csc command, as in ‘csc a.cs’.

Then, run the executable and your dos screen will simply display 'hi' with the bold tag in front of it.

 

To run this exe file from our browser, we key in the following URL in the browser.

 

http://localhost/scripts/a.exe

 

This URL seems logical, since we have placed the file a.exe in the scripts sub-directory. But, we do not seem to get anything right the first time. This is evident from the following errors that have been generated:

 

Output

CGI Error

The specified CGI application misbehaved by not returning a complete set of HTTP headers. The headers it did return are:

hi

 

The first line indicates that we have written a CGI application. CGI stands for Common Gateway Interface. And we have not adhered to the rules pertaining to a CGI application. The web browser expects a complete set of headers, which we have not provided. Subsequently, we see 'hi' displayed in bold.

 

Before moving into the details about the rules, headers etc. of CGI programming, we shall send a header across.

 

a.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("Content-Type:text/html");

System.Console.WriteLine("<b>hi");

}

}

 

We compiled the above program as before and provided the same URL in the browser. It is preferable to load the browser again and provide the URL. You could even click on the refresh icon instead. Whichever method you follow, the same error is generated again.

 

In future, we will not repeat these steps, but we do expect you to follow them, so that your output matches with ours. Writing one more WriteLine function makes no difference at all.

 

a.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("Content-Type:text/html\n");

System.Console.WriteLine("<b>hi");

}

}

 

Output

hi

 

The mere inclusion of an 'enter', represented by '\n', results in elimination of all the errors. We now see the word 'hi' displayed in bold in our window. Before we explain  as to why everything suddenly starts working fine, let us make a small modification in the above program.

 

a.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("Content-Type:text/plain\n");

System.Console.WriteLine("<b>hi");

}

}

 

Output

<b>hi

 

Now, it is time for us to demystify this mystery.

 

 

The web or the HTTP protocol is very simple to understand if you follow certain rules. When the browser requests for a file from the web server, depending upon the extension given to the file, the Web Server does one of the following:

 

     It picks the file up from its local hard disk and sends it across

                                            OR

     It executes the executable file which has been requested for, from the disk which generates this file and sends it over.

 

In the case of a file with a .exe extension, the server executes the file or program on its machine. This program is not restricted to producing an HTML file only. It can create a file of any type. If it were restricted to generating only HTML files, it would have made the web very restrictive.

 

The contents of every file vary depending on the file type. For example, an HTML file will contain tags; a .jpg file will contain images, and so on. The browser must display the files in the right format, on receiving them.

 

To inform the browser about the file coming across, the exe file or program creates a header that signifies the file type or the content type. A header is nothing but a word that is given some value and which ends with a colon. Thus, the phrase 'Content-Type' is a header since it ends in a colon, and the value assigned to it is 'text/plain'.

 

The rules of CGI state that all headers must end with an Enter or '\n' symbol. This is so because a file can have multiple headers. An 'enter' symbol, when placed by itself on a line, signifies the end of all the headers. It also marks the start of the content. The Web server is free to add its own headers to the list of headers generated by the program. This composite data is then transferred to the browser.

 

Since the headers were not specified in the first program, an error was generated. The presence of a Content-Type header in a sense is  mandatory for any file that has to be transferred from the server to the browser.

The second error was reported because we had omitted the 'enter' symbol all by itself, on a separate line, to mark the end of all headers. Thus, more headers were expected from the server. When this did not happen, the browser generated an error. The WriteLine function adds an 'enter' symbol by default, but an additional \n is required all by itself, to indicate an end to the Header values.

 

The browser uses the header named Content-Type, to determine the type of data sent by the web server. Accordingly, it displays the file in the right format.

 

The type text/html refers to a text file containing html tags. Thus, 'hi' was displayed in bold. However, the header value of text/plain informs the browser that plain text content is being sent over, and hence, the tags are not parsed.

 

a.cs

class zzz

{

public static void Main()

{

string s;

System.Console.WriteLine("Content-Type:text/html\n");

s=System.Environment.GetEnvironmentVariable("PATH");

System.Console.WriteLine(s);

}

}

 

Output

C:\Program Files\Microsoft.Net\FrameworkSDK\Bin\;C:\WINNT\Microsoft.NET\Framewor

k\v1.0.2204\;C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;C:\Program Files\Microsoft SQL Server\80\Tools\BINN

 

An environmental variable is a word stored by the operating system. In the world of Windows 2000, if we give the command  >set in the dos box, a list containing a number of words with their corresponding values is displayed.

 

At the command prompt, if we give the command >set aa=hi, it creates an environmental variable named 'aa' and assigns it a value of 'hi' for the current dos session. On issuing the same set command again, this recently created variable and its value, get displayed along with the other environmental values.

 

The namespace System.Environment has a static function called GetEnvironmentVariable. This function accepts an environmental variable name and returns its value. In our program, we ask the function to display the value of the environmental variable named PATH.

 

These variables are created and maintained by the operating system. The web server too can ask the operating system to create some variables, before it executes a program.

 

a.cs

class zzz {

public static void Main()

{

System.Collections.IDictionary i;

i=System.Environment.GetEnvironmentVariables();

System.Collections.IDictionaryEnumerator d;

d=i.GetEnumerator ();

System.Console.WriteLine("Content-Type:text/html\n");

System.Console.WriteLine(i.Count + "<br>");

while (d.MoveNext())

{

System.Console.WriteLine("{0}={1}<br>",d.Key,d.Value);

}

}

}

 

The above program shows 46 environmental variables in the browser. An object named i of datatype IDictionary is defined. It is initialized to the return value of the static function called GetEnvironmentVariables.

 

This function returns an object that contains all the environmental variables. We need a constant way of retrieving data that is similar, but which has multiple occurrences. To do so, the designers of the C# programming language have given us an enumeration object which enables us to list the multiples values.

We use the GetEnumerator function from the object 'i', and store its return value in the enumeration object named 'd'. The object named MoveNext iterates through the list of values. The object contains two members called Key and Value. Basically, the format is Key=Value. Thus, Key stands for the variable name and Value is the value contained in the Key.

 

In the WriteLine function, {0} displays the first parameter, {1} displays the second variable, and so on. The Count member of IDictonary returns the count of the environmental variables.

 

Some of the variables are created by the Operating System while it starts execution. The others are created by the IIS WebServer. We searched the world over, but could not find a variable named Query_String.

 

This program will be used in the future. So we want you to make a copy of it and name it as b.exe:  >copy a.exe b.exe

 

a.html

<html>

<body>

<form action=http://localhost/scripts/a.exe>

<input type = text name = aa>

<input type = text name = bb>

<input type = submit value = click>

</form>

</body>

</html>

 

The above HTML file is placed in the wwwroot sub-directory and loaded as http://localhost/a.html. This file shows two textboxes and a button labeled 'Click'. After entering the words 'hi' and 'bye' in these textboxes, click on the button. You will be surprised to see the browser displaying the same output as shown in the earlier program. But observe that the count now displays the number 48, and the address bar now contains the new URL http://localhost/scripts/a.exe?aa=hi&bb=bye. One of the newly added name-value pair is :

 

QUERY_STRING=aa=hi&bb=bye

 

On receiving the new URL from the web browser, the server simply creates an environmental variable called QUERY_STRING and initializes it with the values that are contained in the URL after the ? symbol. Thereafter, it calls the program named a.exe given in the URL, from the relevant directory.

 

The program on the server can easily identify as to what the user has entered in the textboxes. It simply has to use the Request class or parse the QUERY_STRING variable.

 

Cookies

 

Before taking a leap into this section, we would like you to set a few options in your browser. First, go to menu option 'Tools' and select the last option named 'Internet Options'. Select the Security tab. Ensure that you have selected the ‘Local Intranet’ option and click on Custom level. Scroll down the list box until you see the heading 'Cookies'. For both the sub options, select the 'Prompt' radio button. The default is 'Enable'. Restart the browser after making the changes. Now, run the program given below in your browser.

 

a.cs

class zzz

{

public static void Main()

{

System.Console.WriteLine("Content-Type:text/html\nSet-Cookie:aa=vijay\n");

System.Console.WriteLine("hi");

}

}

 

To our utter surprise, we see a dialog box titled 'Security Alert', asking us whether we would be interested in saving a temporary file sent by the WebServer on our hard disk. This file is termed as cookie.

 

Firstly, we click on the button labeled 'More Info'. This extends the dialog box to give us more information about the cookie.  Notice that the cookie is named as aa, and along with other information, it reveals that the data in this cookie is vijay.

Click on 'yes' and you will see 'hi' in the browser. Subsequently, if you run b.exe in the browser, it will display all our environmental variables as before. But now, an additional environmental variable called HTTP_COOKIE is created with the value of aa=vijay.

 

Before we go further, let us first run the following ASP program in the browser using:

 

http://localhost/a.aspx?aa=hi&bb=bye

 

a.aspx

<html>

<%@ language="C#" %>

<body>

<%

Request.SaveAs("c:\\z.txt",true);

%>

</body>

</html>

 

z.txt

GET /a.aspx?aa=hi&bb=bye HTTP/1.1

Connection: Keep-Alive

Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*

Accept-Encoding: gzip, deflate

Accept-Language: en-us

Host: localhost

User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; COM+ 1.0.2204)

 

For the ones who came in late, whenever we click on a button of type submit, a new URL is generated. The Web browser calls on the WebServer again, and sends it a packet of data.

 

To view the contents of this packet, the Request property is used. This property returns an HttpRequest object. SaveAs is one of the functions in the object that takes two parameters:

 

 

     The filename in which it can save the request.

     A bool value of true or false. If the value is true, the header is also saved in the file.

 

Any packet sent by the browser has two parts to it. It starts with the word GET, followed by the URL that is to be fetched. The name of the computer, localhost, is removed from the URL, as the browser connects to it. Following it is the data, as entered in the browser window.

 

All this is part of the HTTP protocol. The protocol states that the URL is to be followed by the http version number.

 

When the web server sends data to the browser, the packet starts with the headers, followed by a blank line, and finally, followed by the rest of the HTML file. On the other hand, in the packet sent from the browser, the URL is stated first, followed by the data and finally, there are the headers. This is exactly the reverse of what happens in the case of the web server!

 

At first, we run the executable from the browser as http://localhost/scripts/a.exe and accept the cookie. Thereafter, the file a.aspx is copied from c:\inetpub\wwwroot to c:\inetpub\scripts and loaded as http://localhost/scripts/a.aspx. The file named z.txt, is shown below.

 

z.txt

GET /scripts/a.aspx HTTP/1.1

Connection: Keep-Alive

Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*

Accept-Encoding: gzip, deflate

Accept-Language: en-us

Cookie: aa=vijay

Host: localhost

User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; COM+ 1.0.2204)

 

 

A cookie has a header named Set-Cookie, which is sent by the server to the client. A point to be noted here is that the server initiates a cookie, and not a client.

 

There is a program that runs on the server, which directs the server to send a cookie, which has a specific name and value. When the client browser, which could be Netscape, IE or any other browser, sees a header named Set-Cookie, it checks for the cookie-option values. If the prompt is set on, the browser will display a message, thereby, requesting for permission to accept or reject the cookie.

 

If the reply is 'yes', then whenever the client connects to the server, it will contain a header named Cookie, which it will send to the server. Thus, we see the header Cookie: aa=vijay in the file z.txt. The text 'Set-' is removed from the Header.

 

Thus, a cookie is basically a header-value that is sent by the server, and which is returned by the browser.

 

These cookies remain in existence only until the browser is alive. If you close the current copy of the browser and reload it again with the file a.aspx, the cookie header will not be seen.

 

System.Console.WriteLine("Content-Type:text/html\nSet-Cookie:aa=vijay; path=/aa\n");

 

A cookie header, along with the name-value, has a path that decides on the sub-directories that the cookie can be sent to. On running a.exe from the scripts sub-directory, the path parameter in the cookie dialog box shows the path as /scripts/.

 

Therefore, if you load a.aspx from the inetpub\wwwroot sub-directory, it will not show the Cookie: header in the file z.txt. This is because the browser not only stores the domain name or name of the computer, but also the URL or sub-directories that the cookie should be sent to. As the path is /scripts, the browser will only send a Cookie: header to the URLs that access files in the /scripts sub-directory.

 

 

Now, we shall see how our cookies can be made eternal, so that they never say die.

 

a.cs

class zzz

{

public static void Main()

{

System.Console.WriteLine("Content-Type:text/html\nSet-Cookie:aa=Vijay; expires=Tuesday, 03-04-2002 12:12:23\n ");

System.Console.WriteLine("hi");

}

}

 

After leaving a space after the semicolon, we have simply added the word 'expires'. This is initialized to a date in a certain format, followed by time in hours, minutes and seconds. The cookie dialog box( that had earlier displayed the Expires as 'end of session), now displays a specific date.

 

Upto this date, each time we connect to a certain path on the server called localhost, the browser will send this cookie. The earlier cookies were termed as 'session cookies', since their life span extended only till the end of the session. The cookies where 'expires' is mentioned, are called 'non session cookies'. If we disable the cookies, the browser does not send the Cookie: header to the server.

 

Let us now understand the Response and Request objects in ASP.Net, which are introduced when they are derived from the Page class.

 

The Request Object

 

The property Request in the Page class, is of type HttpRequest, and it contains code that handles the data sent by the browser.

 

This makes it easier for our aspx program to parse the output sent to us by the browser.

 

a.aspx

<html>

<%@ language="C#" %>

<body>

<%

String[] s = Request.AcceptTypes;   

Response.Write(s.Length.ToString());

for (int i = 0; i < s.Length; i++)

{

Response.Write(s[i] + "<br>");

}

%>

</body>

</html>

 

Output

8image/gif

image/x-xbitmap

image/jpeg

image/pjpeg

application/vnd.ms-powerpoint

application/vnd.ms-excel

application/msword

*/*

 

The web server sends the header Content-Type to signify the type of content that is to follow. The type given after Content-Type is also called the 'MIME type'. The client, i.e. the browser too sends across the types it supports, by using a header called Accept.

 

This header is sent as follows:

 

Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*

 

Thus, the MIME type starts with the name of a family, such as image, text, application etc. This is followed by a slash /, after which we specify the different types within the family. The symbol */* indicates that the browser supports all MIME types.

 

The Request object has a property called AccessTypes, which returns an array of strings. We simply display them using a 'for' loop. The Length property gives us the number of members present in the array.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.ApplicationPath);

%>

 

Output

/

 

The property ApplicationPath displays the virtual path to the currently running server application. Even if you copy the file in the scripts sub-directory and change the URL to http://localhost/scripts/a.aspx, the result will still be a slash i.e. /.

 

a.aspx

<%@ language="C#" %>

<%

HttpBrowserCapabilities b = Request.Browser;

Response.Write("Type = " + b.Type + "<br>");

Response.Write("Name = " + b.Browser + "<br>");

Response.Write("Version = " + b.Version + "<br>");

Response.Write("Major Version = " + b.MajorVersion + "<br>");

Response.Write("Minor Version = " + b.MinorVersion + "<br>");

Response.Write("Platform = " + b.Platform + "<br>");

Response.Write("Is Beta = " + b.Beta + "<br>");

Response.Write("Is Crawler = " + b.Crawler + "<br>");

Response.Write("Is AOL = " + b.AOL + "<br>");

Response.Write("Is Win16 = " + b.Win16 + "<br>");

Response.Write("Is Win32 = " + b.Win32 + "<br>");

Response.Write("Supports Frames = " + b.Frames + "<br>");

Response.Write("Supports Tables = " + b.Tables + "<br>");

Response.Write("Supports Cookies = " + b.Cookies + "<br>");

Response.Write("Supports VB Script = " + b.VBScript + "<br>");

Response.Write("Supports Java Script = " + b.JavaScript + "<br>");

Response.Write("Supports Java Applets = " + b.JavaApplets + "<br>");

Response.Write("Supports ActiveX Controls = " + b.ActiveXControls + "<br>");

Response.Write("CDF = " + b.CDF + "<br>");

%>

 

Output

Type = IE5

Name = IE

Version = 5.5

Major Version = 5

Minor Version = 0.5

Platform = WinNT

Is Beta = False

Is Crawler = False

Is AOL = False

Is Win16 = False

Is Win32 = True

Supports Frames = True

Supports Tables = True

Supports Cookies = True

Supports VB Script = True

Supports Java Script = True

Supports Java Applets = True

Supports ActiveX Controls = True

CDF = False

 

The Browser property in the Request Object returns an object of type HttpBrowserCapabilities. Thus, an object b of this type is created and it stores the return value of this property. We then display all the members of this class, which consist of the features of the browser that just connected to the server.

 

Depending upon the values that are supported and returned by the browser, the aspx file can be made generic, to enable it to handle the differences among browsers.

 

The type member returns the name of the browser along with its version number, whereas, the Browser property returns only the name. The version number is displayed as 5.5. We can even display the major and the minor version numbers separately. It is mandatory to have the Version of the Explorer greater than 5.0, otherwise, the .Net framework does not reveal the right values.

The property named 'Platform' informs us about the Operating System that the browser is running on. If the browser is currently running on Windows 2000, the platform property still displays the value as WinNT. Our version of IE is the final copy, and not the beta version, hence, the value of the property named beta is shown as false.

 

Search engines crawl all over, looking for websites. Since ours is a simple browser, the property named IsCrawler is shown as false. America Online is the largest on-line service in the world and it has its own branded browser. Since we are using IE from Microsoft, the property named AOL has a value of false.

 

Earlier, Microsoft had a 16 bit operating system called Windows 3.1. As we are presently running their 32 bit Operating system, the property Win16 is false, while the property Win32 is true. An HTML page is divided into smaller parts by frames. Today, all browsers support frames. Thus, the Frames property has a value of true.

 

Earlier some browsers could not display tables. Thus, the tables property was introduced in the object. Today, all the browsers fully support tables. However, not every browser can run Java applets within the browser. In our case, since IE can do so, the JavaApplets property is true.

 

All browsers support cookies, since it is a standard created by Netscape. We have two main client side scripting languages, VBScript from Microsoft and Javascript from Netscape. Since our browser supports both, their properties are true. And since ActiveX was invented by Microsoft, this property also has a value of true.

 

Finally, if we want to webcast something, there is a new format called Channel Definition Format or CDF, which has to be used. For some reason, IE does not support it.

 

a.aspx

<%@ language="C#" %>

<%

Encoding e = Request.ContentEncoding;

Response.Write(e.EncodingName); %>

Output

Unicode (UTF-8)

 

The Request.ContentEncoding property returns an Encoding object. This object also has a large number of properties and methods. One of them is called EncodingName, which reveals the Character Set that the browser uses to transfer data to and fro.

 

a.cs

class zzz

{

public static void Main()

{

System.Console.WriteLine("Content-Type:text/html");

System.Console.WriteLine("Set-Cookie:aa=vijay0; expires=Tuesday, 09-09-2001 12:12:23");

System.Console.WriteLine("Set-Cookie:a1=vijay1; expires=Tuesday, 09-09-2001 12:12:23");

System.Console.WriteLine("Set-Cookie:a2=vijay2; expires=Wednesday, 10-10-2001 12:12:23\n");

System.Console.WriteLine("hi");

}

}

 

We first loaded the following C# executable from the script sub-directory:

 

http://localhost/scripts/a.exe

 

This sets three cookies for the browser session, which is currently active.

 

Then, we ran the aspx program (as given below) from the scripts sub-directory, using:

 

http://localhost/scripts/a.aspx

 

a.aspx

<%@ language="C#" %>

<%

HttpCookieCollection cc;

cc = Request.Cookies;

Response.Write(cc.Count.ToString() + "<br>");

for (int i  = 0; i < cc.Count; i++)

{

HttpCookie c = cc[i];

Response.Write(c.Name + "=" + c.Value + "<br>");

}

%>

 

Output

4

aa=vijay0

a1=vijay1

a2=vijay2

ASP.NET_SessionId=wnyumy5544u3tj55tdrp0u45

 

Request.Cookies returns an HttpCookieCollection object that is stored in the object cc. This object named cc has a member named count, which returns a count of the number of cookies present in the collection. We have 4 cookies, and hence, the 'for' loop is repeated four times.

 

HttpCookieCollection has an indexer that allows access to the individual cookies. Thus, cc[0] refers to the first HttpCookie object, and so on. The HttpCookie class in turn, has two important members, i.e. Name and Value, which display the name of the cookie and its value, respectively.

 

a.aspx

<%@ language="C#" %>

<%

HttpCookieCollection cc;

cc = Request.Cookies;

HttpCookie c = cc["a1"];

Response.Write(c.Name + "=" + c.Value + "<br>");

%>

 

Output

a1=vijay1

 

 

The indexer in the HttpCookieCollection object can also accept a string, which is the name of the cookie. It returns a cookie object that represents that cookie. The Value member will display the value contained in the cookie. This will retrieve only a single cookie.  

 

a.aspx

<%@ language="C#" %>

<%

HttpCookieCollection cc;

HttpCookie c;

cc = Request.Cookies;

String[] s = cc.AllKeys;

for (int i  = 0; i < s.Length; i++)

{

Response.Write(s[i] + "<br>");

}

for (int i  = 0; i < s.Length; i++)

{

c = cc[s[i]];

Response.Write("Cookie: " + c.Name + " ");

Response.Write("Expires: " +c.Expires + " ");

Response.Write ("Secure:" + c.Secure + " ");

String[] s1 = c.Values.AllKeys;

for (int j  = 0; j  < s1.Length; j++)

{

Response.Write("Value" + j + ": " + s1[j] + "<br>");

}

}

%>

 

Output

aa

a1

a2

langpref

ASP.NET_SessionId

Cookie: aa Expires: 1/1/0001 12:00:00 AM Secure:False Value0:

Cookie: a1 Expires: 1/1/0001 12:00:00 AM Secure:False Value0:

Cookie: a2 Expires: 1/1/0001 12:00:00 AM Secure:False Value0:

Cookie: langpref Expires: 1/1/0001 12:00:00 AM Secure:False Value0:

Cookie: ASP.NET_SessionId Expires: 1/1/0001 12:00:00 AM Secure:False Value0:

 

 

Just as there are many ways to skin a cat, there are also numerous ways of displaying a cookie. The HttpCookiecollection class has a member called AllKeys that returns an array of strings, which represent the names of the cookies or its keys. Thus, in one stroke, we can figure out all the names of the cookies.

 

After displaying the individual names of the Cookie in the 'for' loop, the same name is used in the indexer, to access the individual cookie object. The 'expires' property inexplicably, does not display the correct date and time. Further, the Values object must be used in place of the Value property, because a cookie can have multiple values. Thus, c.Values.AllKeys returns an array of strings. Since in the present case, every cookie has only a single value, the 'for' loop executes only once.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.FilePath);

%>

 

Output

/a.aspx

 

The property named FilePath returns the virtual path of the request. The output reflected is  /aspx, because we are loading this file from the wwwroot sub-directory. If you run the file from the scripts sub-directory, the output will display /scripts/a.aspx

 

a.aspx

<%@ language="C#" %>

<%

NameValueCollection c;

c=Request.Headers;

String[] s = c.AllKeys;

for (int i  = 0; i < s.Length; i++)

{

Response.Write("Key: " + s[i] + " ");

String[] s1=c.GetValues(s[i]);

for (int j = 0; j<s1.Length; j++)

{

Response.Write("Value " + j + ": " + s1[j] + "<br>");

}

}

%>

 

Output

Key: Connection Value 0: Keep-Alive

Key: Accept Value 0: */*

Key: Accept-Encoding Value 0: gzip, deflate

Key: Accept-Language Value 0: en-us

Key: Cookie Value 0: langpref=C#; ASP.NET_SessionId=abksbkrxdgjmmj45hasiffzx

Key: Host Value 0: localhost

Key: User-Agent Value 0: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914)

 

The Headers property returns a NameValueCollection object that represents all the headers. The rules for handling headers are common for all headers. The rules are all in the form of name=value. The object c has an AllKeys property, which returns a list of keys. As before, we use a loop and call the function GetValues, which returns an array of strings when it is supplied with a key value. Most of the time, we only have a single value. Hence, our array s1 has a length of one.

 

a.aspx

<%@ language="C#" %>

<%

NameValueCollection c;

c=Request.Headers;

String[] s = c.AllKeys;

for (int i  = 0; i < s.Length; i++)

{

Response.Write("Key: " + c[i] + " ");

String s1=c.Get(s[i]);

String s2=c.Get(i);

Response.Write("Value " + s1 + " " + s2 + "<br>");

}

%>

 

 

Output

Key: Keep-Alive Value Keep-Alive Keep-Alive

Key: */* Value */* */*

Key: gzip, deflate Value gzip, deflate gzip, deflate

Key: en-us Value en-us en-us

Key: langpref=C#; ASP.NET_SessionId=abksbkrxdgjmmj45hasiffzx Value langpref=C#; ASP.NET_SessionId=abksbkrxdgjmmj45hasiffzx langpref=C#; ASP.NET_SessionId=abksbkrxdgjmmj45hasiffzx

Key: localhost Value localhost localhost

Key: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914) Value Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914) Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914)

 

The output is the same as before, but it is easier to comprehend now, since a function called Get is used, which returns a single string value. Every value is displayed twice, because we have used both the forms of the Get function, i.e. passing it a string and then, passing it a number. It is the browser that sends these headers. You can easily verify this by inspecting the file z.txt, which has been created earlier.

 

Let us first create a simple aspx file that merely writes out the value of a property called HttpMethod.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.HttpMethod);

%>

 

a.html

<html>

<body>

<form action=http://localhost/a.aspx METHOD=GET>

<input type = text name = aa>

<input type = text name = bb>

<input type = submit value = click>

</form>

</body>

</html>

In the above HTML file, we have added an attribute called 'METHOD=GET' to the form tag. When we click on the 'click' button, browser screen loads on, with the address containing the action value of http://localhost/a.aspx, followed by the ? symbol and the name value pairs. The word GET is also displayed in the browser window.

 

Now, we make a small modification in the HTML file. We replace the words GET with POST. When we load the file, everything remains the same. When we click on the button, the browser now displays POST. Further, the URL contained in the address bar does not contain either the question mark or the name-value pairs.

 

The difference between a GET and POST method is that, in a POST, the data is transmitted as a separate packet, whereas, in a GET, it is sent as part of the URL. In Get, there is a limit to the amount of data that can be sent as part of the URL. Passwords and other important information must always be sent using the POST method and not the GET method.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.IsAuthenticated + "<br>");

Response.Write(Request.IsSecureConnection + "<br>");

%>

 

Output

False

False

 

We have neither authenticated our connection, nor have we been using a secure connection. A secure connection begins with 'https', instead of 'http'.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.Path);

%>

 

Output

/a.aspx

 

This property displays the virtual path of the current request.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.PhysicalApplicationPath);

%>

 

Output

c:\inetpub\wwwroot\

 

The Web Server can be installed anywhere on the hard disk. The default directory selected by IIS is C:\inetpub\wwwroot. As we have used the defaults, the property PhysicalApplicationPath reveals the same path. The PhysicalApplicationPath is called the home directory or the root directory of IIS. Whenever a file is to be referred to on the hard disk, this value is added to the filename. Further, the slash symbol /, which represents the virtual directory, finally gets converted into this physical path, while it is locating or sending files to the browser.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.PhysicalPath);

%>

 

Output

c:\inetpub\wwwroot\a.aspx

 

In this program, we go a step further and ask for the full path name or the physical filename of our aspx file.

 

For the next program, we write the following URL in the browser:

 

http://localhost/a.aspx?aa=hi&bb=bye&aa=no

 

 

a.aspx

<%@ language="C#" %>

<%

NameValueCollection c=Request.QueryString;

String[] s = c.AllKeys;

for (int i  = 0; i < s.Length; i++)

{

Response.Write(s[i] + " ");

String[] s1 = c.GetValues(s[i]);

for (int j = 0; j < s1.Length; j++)

{

Response.Write("Value " + j + ": " + s1[j] + " ");

}

Response.Write("<br>");

}

%>

 

Output

aa Value 0: hi Value 1: no

bb Value 0: bye

 

The QueryString  property returns a NameValueCollection. The AllKeys property of this object returns only two keys, which is because we have repeated the parameter name aa twice. We are permitted to repeat names in HTML.

 

The 'for' loop is repeated twice for the two keys. The GetValues function returns an array consisting of two members for aa, which is because it contains two values i.e. 'hi' and 'no'. The second 'for' loop displays these values.

 

Working with ASP+ is a pleasure, since there is an inbuilt code for handling multiple values.

 

If we run the earlier HTML file with the method as Post, we shall not receive any output, because the environmental variable QueryString holds values only with the Get method.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.RawUrl);

%>

 

Output

/a.aspx

 

The RawUrl displays the URL in its most primitive form.

 

a.aspx

<%@ language="C#" %>

<%

NameValueCollection c;

c=Request.ServerVariables;

String [] s = c.AllKeys;

for (int i = 0; i < s.Length; i++)

{

Response.Write(s[i] + "=");

String [] s1 =c.GetValues(s[i]);

for (int j = 0; j < s1.Length; j++)

{

Response.Write(s1[j] + " ");

}

Response.Write("<br>");

}

%>

 

Output

ALL_HTTP=HTTP_CONNECTION:Keep-Alive HTTP_ACCEPT:*/* HTTP_ACCEPT_ENCODING:gzip, deflate HTTP_ACCEPT_LANGUAGE:en-us HTTP_COOKIE:langpref=C#; ASP.NET_SessionId=abksbkrxdgjmmj45hasiffzx HTTP_HOST:localhost HTTP_USER_AGENT:Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914)

ALL_RAW=Connection: Keep-Alive Accept: */* Accept-Encoding: gzip, deflate Accept-Language: en-us Cookie: langpref=C#; ASP.NET_SessionId=abksbkrxdgjmmj45hasiffzx Host: localhost User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914)

APPL_MD_PATH=/LM/W3SVC/1/ROOT

APPL_PHYSICAL_PATH=c:\inetpub\wwwroot\

CONTENT_LENGTH=0

CONTENT_TYPE=

GATEWAY_INTERFACE=CGI/1.1

HTTPS=off

INSTANCE_ID=1

INSTANCE_META_PATH=/LM/W3SVC/1

LOCAL_ADDR=127.0.0.1

PATH_INFO=/a.aspx

PATH_TRANSLATED=c:\inetpub\wwwroot\a.aspx

QUERY_STRING=

REMOTE_ADDR=127.0.0.1

REMOTE_HOST=127.0.0.1

REQUEST_METHOD=GET

SCRIPT_NAME=/a.aspx

SERVER_NAME=localhost

SERVER_PORT=80

SERVER_PORT_SECURE=0

SERVER_PROTOCOL=HTTP/1.1

SERVER_SOFTWARE=Microsoft-IIS/5.0

URL=/a.aspx

HTTP_CONNECTION=Keep-Alive

HTTP_ACCEPT=*/*

HTTP_ACCEPT_ENCODING=gzip, deflate

HTTP_ACCEPT_LANGUAGE=en-us

HTTP_COOKIE=langpref=C#; ASP.NET_SessionId=abksbkrxdgjmmj45hasiffzx

HTTP_HOST=localhost

HTTP_USER_AGENT=Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914)

 

The server creates a large number of variables. They are too numerous to be displayed. Here, we are only displaying the variables that have values.

 

a.aspx

<%@ language="C#" %>

<%

Uri o = Request.Url;

Response.Write("URL Port: " + o.Port + "<br>");

Response.Write("URL Protocol: " + o.Scheme + "<br>");

Response.Write("URL Host: " + o.Host + "<br>");

Response.Write("URL PathAndQuery: " + o.PathAndQuery + "<br>");

Response.Write("URL Query: " + o.Query + "<br>");

%>

Output

URL Port: 80

URL Protocol: http

URL Host: localhost

URL PathAndQuery: /a.aspx?aa=hi&bb=bye

URL Query: ?aa=hi&bb=bye

 

The Url property in the Request object, returns an HttpUrl object. This object has many properties, which break up the URL into different components. The port number is related to the protocol used.

 

Every packet on the Internet is tagged with a number that signifies the protocol that carries it. For e.g., the http protocol has the port no. 80, E-Mail read is 25, FTP is 21, etc.  Thus, the Port shows a value of 80 because the URL that has been entered, starts with the syntax http:. Similarly, the protocol used is http.

 

Host is the name of our computer. PathAndQuery contains the name of the requested file along with the querystring.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.UserAgent);

%>

 

Output

Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914)

 

A user agent is another name for the browser. The internal name for Netscape was Mozilla. So, IE initially referred to itself by the same name. Many of the websites performed a check on the browser that was requesting for the file. If it matched IE, the page was not sent across. However, today it is IE that has eventually won the browser war. We shall talk about it later, since it is too long an account to be related to you right away.

 

 

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Request.UserHostAddress);

%>

 

Output

127.0.0.1

 

Every computer on the Internet is known by a number, which is technically called an IP address. It is of a long data type. This implies that it consists 4 numbers, each ranging from 0 to 255. These numbers are separated by dots. This format is known as the decimal dotted notation.

 

As every machine is known as localhost and it is given an IP address 127.0.0.1. Thus, when we write localhost in the IE address bar, it gets converted to 127.0.0.1.

 

a.aspx

<%@ language="C#" %>

<%

String[] s = Request.UserLanguages;   

for (int i = 0; i < s.Length; i++)

{

Response.Write(s[i] + "<br>");

}

%>

 

Output

en-us

 

The property UserLanguages returns the languages that the browser supports. In our case, the browser supports the English language, or more precisely, 'en-us', which stands for   American English and not for British English.

 

a.aspx

<%@ language="C#" %>

<%

String s = Request.MapPath("/quickstart");

Response.Write(s);

%>

 

Output

C:\Program Files\Microsoft.Net\FrameworkSDK\Samples\QuickStart

 

When the .Net sdk installs itself, it creates virtual directories in IIS. Thus, when we write http://localhost/quickstart, it converts the virtual directory named quickstart to the path displayed above. The MapPath function in the Request Object, converts a virtual directory to an absolute path on your hard disk.

 

The Response Object

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Response.BufferOutput.ToString());

%>

 

Output

True

 

The first property we delve upon in the HttpResponse class is BufferOutput. This property returns a logical value of either a True or False. In doing so, it keeps us posted  on whether the output sent to the browser will be buffered or not.

 

While using the Write function from the Response class, the data doesn't have to be sent to the browser at once, as this will result in too many small packets being sent across. Therefore, on grounds of efficiency, the text is collected and sent only when a critical mass is reached. By default, the buffering option is on. Unless you are equipped with a valid reason, you should not turn it off.

 

a.aspx

<%@ language="C#" %>

<%

Response.ContentType = "Text/plain";

Response.Write("<b>hi");

%>

Output

<b> hi

 

The web server sends a series of headers to the browser. It then follows it up with the actual content. As explained to you earlier, the most important header is Content-Type. If we avoid creating this header in our file, IIS defaults to the type value as text/html.

Here, we have changed the Content-Type property in Response to text/plain. Thus, the <b> tag is treated as text and not a HTML tag.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write(Response.IsClientConnected.ToString());

%>

 

Output

True

 

This function simply returns true or false, depending on whether the client is connected or not. This is one check that is to be performed before we send the file to the browser.

 

a.aspx

<%@ language="C#" %>

<%

System.IO.FileStream f;

long s;

f = new System.IO.FileStream("c:\\inetpub\\wwwroot\\a.html", System.IO.FileMode.Open);

byte[] b = new byte[(int)f.Length];

f.Read(b, 0, (int)f.Length);

Response.Write("<b>Start a.spx</b>");

Response.BinaryWrite(b);

Response.Write("<b>End a.spx</b>");

%>

 

Output

 

In the System.IO namespace, there is a class called FileStream, which has members that can handle file activity. While creating an object 'f' in the constructor, we state the full path of the file and also the mode in which the file is to be opened. We then allocate a byte array, depending upon the size of the file. The file size is acquired using the property called Length in the FileStream object.

 

The read function is employed next, to read the file into the byte buffer. Therefore, the first parameter specified is 'b'. The second parameter is the starting position in the file, the position from where the reading should begin. And the last parameter is the number of bytes to be read, from thereon. As we want to read from the beginning of the file, and we also want to read the entire file in one go, we specify zero as the second parameter and the length of the file is the third parameter.

 

Now that the file is available in the byte array, the BinaryWriter function is used to add these bytes into a stream and subsequently, send them to the browser. As the browser receives an HTML file, it parses through the file and displays the textboxes. The Write functions before and after the BinaryWrite, work as normal.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write("<b>Start");

Response.ContentType = "Text/plain";

Response.Clear();

Response.Write("<b>End");

%>

 

Output

<b>End

 

The Response.ContentType function initially changes the Content-Type header after writing Start in bold. Thereafter, the Clear function in Response, clears all HTML output, since its job is to clear the Buffer. So, the output displayed in the browser is that of the final Write. Even though the documentation states that headers are reset, it does not happen in the case of our copy.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write("<b>Start");

Response.ContentType = "Text/plain";

Response.ClearHeaders();

Response.Write("<b>End");

%>

 

Output

StartEnd

 

However, the function ClearHeaders, resets all the headers created in the scriptlet. Thus, the default Content-type header is sent across, before the contents in the buffer are handed over to the browser. As a result, we see StartEnd displayed in bold.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write("<b>Start");

Response.End();

Response.Write("<b>End");

%>

 

Output

Start

 

The End function states 'enough is enough', and it sends across the HTML file and the headers immediately. Thereafter, it closes the connection. Thus, all future output to be sent to the browser, is conveniently ignored.

 

 

a.aspx

<%@ language="C#" %>

<%

Response.Write("<b>Start");

Response.Redirect("a1.aspx");

Response.Write("<b>End");

%>

 

a1.aspx

<%@ language="C#" %>

<%

Response.Write("<b>a1.aspx");

%>

 

Output

a1.aspx

 

The redirect function merely stops executing the current file, a.aspx, and starts executing the file to which it has been redirected. Thus, in case of a Redirect function, any Write function that follows the Redirect command, is completely ignored. Also, if you observe the address bar, the URL does not change in the browser. It remaines as a.aspx.

 

a.aspx

<%@ language="C#" %>

<%

Response.Write("a.aspx <br>");

Response.WriteFile("a.html");

%>

 

The output is similar to one of the earlier programs. The WriteFile function writes the file contents into the http stream and sends it to the browser.

 

Cookies Revisited

 

a.aspx

<%@ language="C#" %>

<%

HttpCookie c = new HttpCookie("vijay","mukhi");

Response.AppendCookie(c);

%>

 

One of the simplest things to do in ASP+, is to send a cookie across. Object 'c' of type HttpCookie is created by calling the constructor with the name of the cookie vijay, having a value of mukhi.

 

Since the cookie option has been set to prompt in the browser, you will see Alert box for the cookie. Please note that the constructor does not send the cookie across. It is the function AppendCookie that does so.

 

a.aspx

<%@ language="C#" %>

<%

HttpCookie c = new HttpCookie("vijay","mukhi");

Response.AppendCookie(c);

HttpCookie c1 = new HttpCookie("vijay1","mukhi1");

Response.AppendCookie(c1);

c = new HttpCookie("vijay1","mukhi2");

Response.AppendCookie(c);

%>

 

By default, the browser sends a cookie for the ASP+ session. In the above program, even though three cookies have been sent, we see only two boxes, since the second and the third cookies share the same name. Thus, the cookie with the names of vijay1 and value mukhi2 is not sent across separately. The point to be considered here is that you are free to send as many cookies as you like.

 

a.aspx

<%@ language="C#" %>

<%

HttpCookie c = new HttpCookie("vijay");

c.Values.Add("sonal","wife");

c.Values.Add("zzz","yyy");

Response.AppendCookie(c);

%>

 

Output

Value in cookie dialog box

sonal=wife&zzz=yyy

 

a1.aspx

<%@ language="C#" %>

<%

HttpCookieCollection cc;

HttpCookie c;

cc = Request.Cookies;

int i = cc.Count;

for (int k = 0; k < i; k++)

{

c = cc[k];

Response.Write("Cookie: " + c.Name + "<br>");

String[] s1 = c.Values.AllKeys;

for (int j  = 0; j  < s1.Length; j++)

{

Response.Write("Value" + j + ": " + s1[j] + "<br>");

}

}

%>

 

Output

Cookie: vijay

Value0: sonal

Value1: zzz

Cookie: ASP.NET_SessionId

Value0:

 

Cookies can be made as complex as we like. We create one cookie named vijay, and then use the Add function in the Values property of the cookie, to initialize the subnames and values for the cookie.

 

The cookie is transferred as one entity, with the key-value pairs within it. The different pairs are separated by a & sign. a1.aspx simply displays all the cookies. For a cookie named vijay, the last 'for' loop gets executed twice as it holds two values.

 

a1.aspx

<%@ language="C#" %>

<%

HttpCookieCollection cc;

HttpCookie c;

cc = Request.Cookies;

c = cc["vijay"];

Response.Write("Cookie: " + c.Name + "<br>");

Response.Write(c.Values["sonal"] + "<br>");

Response.Write(c.Values["zzz"]);

%>

 

Output

Cookie: vijay

wife

yyy

 

Rewrite a1.aspx with the code given above. This program first fetches the cookie named vijay and stores it in 'c'. The Values property, which returns a NameValueCollection, has an indexer that is supplied with the name of the sub key. Consequently, this indexer returns the value of the sub key.

 

a.aspx

<html>

Sonal Mukhi

<a href="a1.aspx">Click here</a>

</html>

 

a1.aspx

<html>

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs E)

{

if (!IsPostBack) {

Response.Write(Request.Headers["Referer"]);

ViewState["zzz"] = Request.Headers["Referer"];

}

}

void abc(Object sender, EventArgs E) {

Response.Redirect(ViewState["zzz"].ToString());

}

</script>

<form runat="server">

<input type="submit" OnServerClick="abc" Value="Click" runat="server"/>

</form>

</body>

</html>

 

Output

Sonal Mukhi Click here

 

http://localhost/a.aspx

 

The file a.aspx has an anchor tag <a href…> that takes us to page a1.aspx, whenever we click on it.

 

The ASP+ program a1.aspx displays a button with the label 'click'. Prior to this, the function Page_Load is called. This function uses the Request object to access the indexer called Header. The Header is passed a string called Referer, which informs it about the file of its origin. As a.aspx was responsible for leading us to a1.aspx from a.aspx, the URL displays the file name a.aspx.

 

The WebServer normally keeps a log of the files that lead a user to its site. This value is then stored in a state variable called zzz. As we are now aware of the site that brought us to the current one, by clicking on the button, we can Redirect ourselves to the page we came from.

 

Thus, the above code is generic and goes into a circular loop.

 

We shall now consider a practical example to demonstrate the utility of cookies.

 

a.aspx

<html>

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs E)

{

if (Request.Cookies["vijay"] == null)

{

HttpCookie c = new HttpCookie("vijay");

c.Values.Add("Size","8pt");

c.Values.Add("Name","Verdana");

Response.AppendCookie(c);

}

}

public String abc(String k)

{

HttpCookie c = Request.Cookies["vijay"];

if (c != null)

{

if ( k == "FontSize")

return c.Values["Size"];

else

return c.Values["Name"];

}

return "";

}

</script>

<style>

body

{

font: <%=abc("FontSize")%> <%=abc("FontName")%>

}

</style>

Sonal Mukhi

<a href="a1.aspx">Click here</a>

</body>

</html>

 

a1.aspx

<html>

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs E)

{

if (!IsPostBack)

ViewState["zzz"] = Request.Headers["Referer"];

}

void abc(Object sender, EventArgs E)

{

HttpCookie c = new HttpCookie("vijay");

c.Values.Add("Size",s1.Value);

c.Values.Add("Name",s2.Value);

Response.AppendCookie(c);

Response.Redirect(ViewState["zzz"].ToString());

}

</script>

<form runat="server">

<select id="s1" runat="server">

<option>8pt</option>

<option>10pt</option>

<option>12pt</option>

<option>44pt</option>

</select>

<select id="s2" runat="server">

<option>verdana</option>

<option>tahoma</option>

<option>arial</option>

<option>times</option>

</select>

<input type="submit" OnServerClick="abc" Value="Click" runat="server"/>

</form>

</body>

</html>

 

Output

Sonal Mukhi Click here

 

Sonal Mukhi Click here

 

The above example displays the text 'Sonal Mukhi' and a hyperlink labelled as 'Click Here'. If we click on the hyper link, we are transported to a new page called a1.aspx.  This page contains two dropdown listboxes and a button. The first listbox displays the font point size and the second offers the font face name. By default, the values in these text boxes are 8pt for the font size and Verdana for the font face name, respectively. At this stage, if you modify the font size to 12 and the font face name to Tahoma, and then click on the button, you will be taken back to the original file named a.aspx. In this file, the text and the Hyperlink will now be displayed in the newly selected font and size.

Having unravelled the output, let us now shift the spot-light to the internal working of this program.

 

The Page_Load function in a.aspx