Posting data
4.2.5 Posting data
Many dynamic Web sites contain forms for login details, search criteria, or similar data. These forms are usually submitted via the POST method. This poses a problem, however, for any application that needs to query a page that lies behind such a form because you cannot specify posted data in the URL line.
Chapter 4
98 4.2 HTTP
First, prepare a page that handles POST requests. In this case, type the fol- lowing lines into a file called postTest.aspx in c:\inetpub\wwwroot (your HTTP root):
ASP.NET
<%@ Page language="c#" Debug="true"%> <script language="C#" runat="server">
public void Page_Load(Object sender, EventArgs E) {
if (Request.Form["tbPost"]!=null) {
Response.Write(Request.Form["tbPost"].ToString()); } } </script>
<form method="post">
<input type="text" name="tbpost"> <input type="submit">
</form>
ASP.NET is a vast subject that lies outside the scope of this book; how- ever, for the sake of explaining the above example, a quick introduction is necessary. ASP.NET is an extension to IIS that enables .NET code to be executed on receipt of requests for Web pages. This also provides means for .NET code to dynamically generate responses to clients in the form of HTML, viewable on Web browsers.
Incoming requests and outgoing data are mapped to objects in .NET, which can easily be read and manipulated. The most fundamental of these objects are the Request and Response objects. The Request object encapsu- lates the data sent from the Web browser to the server; of its properties, two of the most important are the Form and QueryString collections. The Form collection reads data sent from the client via the POST method, whereas the QueryString collection reads data sent from the client via the GET method.
The Response object places data on the outgoing HTTP stream to be sent to the client. One of its most important methods is Write . This method is passed a string that will be rendered as HTML on the client.
One of the features that makes ASP.NET more powerful than its predeces- sor, classic ASP, is its ability to model HTML elements as objects, not merely
4.2 HTTP 99
as input and output streams. For example, an input box would be typically written in ASP.NET as <ASP:TEXTBOX id=”tbText” runat=”server”/> , and the properties of this textbox could then be modified from code by accessing the tbText object. In classic ASP, the only way to achieve such an effect would be to include code within the textbox declaration, such as <input type=”text” <%=someCode%>> , which is less desirable because functional code is intermixed with HTML.
ASP.NET provides better performance than classic ASP because it is compiled on first access (in-line model) or precompiled (code-behind model). It also leverages the .NET framework, which is much richer than the scripting languages available to ASP.
The example above is appropriate for demonstrating the posting method. Every Web scripting language handles posted data in much the same way, so the technique is applicable to interfacing with any Web form.
Web scripting languages share a common feature: some sections of the page are rendered on the browser screen as HTML, and some are processed by the server and not displayed on the client. In the example, anything marked runat=”server” or prefixed <% will be processed by the server.
When the user presses the submit button ( <input type=”submit”> ), the browser packages any user-entered data that was contained within the <form> tags and passes it back to the server as a POST request.
The server parses out the data in the POST request once it is received. The server-side script can retrieve this data by accessing the Request.Form collection. The Response.Write command prints this data back out to the browser.
To try the page out, open a browser and point it at http://localhost/post- Test.aspx; type something into the textbox, and press Submit. Then you will see the page refresh, and the text you typed appears above the form.
Reopen the previous example and add a new textbox named tbPost . Click on the Capture button and modify the code as follows:
C#
private void btnCapture_Click(object sender, System.EventArgs e)
{ tbPost.Text = HttpUtility.UrlEncode(tbPost.Text); tbResult.Text =
getHTTP(tbUrl.Text,"tbPost="+tbPost.Text); }
Chapter 4
100 4.2 HTTP
VB.NET
Private Sub btnCapture_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btnCapture.Click
tbPost.Text = HttpUtility.UrlEncode(tbPost.Text) tbResult.Text = getHTTP(tbUrl.Text,"tbPost="+tbPost.Text)
End Sub
The reason for the call to HttpUtility.UrlEncode is to convert the text entered by the user into a string that is safe for transport by HTTP. This means the removal of white space (spaces are converted to “+”) and the con- version of nonalphanumeric characters, which is a requirement of the HTTP protocol.
Once the data to post is encoded, it can be passed to the getHTTP func- tion, which is described below. It is a modified version of the code previ- ously listed.
C#
public string getHTTP(string szURL,string szPost) {
HttpWebRequest httprequest; HttpWebResponse httpresponse; StreamReader bodyreader; string bodytext = ""; Stream responsestream; Stream requestStream;
httprequest = (HttpWebRequest) WebRequest.Create(szURL); httprequest.Method = "POST"; httprequest.ContentType = "application/x-www-form-urlencoded"; httprequest.ContentLength = szPost.Length; requestStream = httprequest.GetRequestStream(); requestStream.Write(Encoding.ASCII.GetBytes(szPost),0, szPost.Length); requestStream.Close(); httpresponse = (HttpWebResponse) httprequest.GetResponse(); responsestream = httpresponse.GetResponseStream(); bodyreader = new StreamReader(responsestream); bodytext = bodyreader.ReadToEnd(); return bodytext;
4.2 HTTP 101
VB.NET
Public Function getHTTP(ByVal szURL As String, _ ByVal szPost As String) As String
Dim httprequest As HttpWebRequest Dim httpresponse As HttpWebResponse Dim bodyreader As StreamReader Dim bodytext As String = "" Dim responsestream As Stream Dim requestStream As Stream
httprequest = CType(WebRequest.Create(szURL), _ HttpWebRequest) httprequest.Method = "POST" httprequest.ContentType = _ "application/x-www-form-urlencoded" httprequest.ContentLength = szPost.Length requestStream = httprequest.GetRequestStream() requestStream.Write(Encoding.ASCII.GetBytes(szPost), _ 0,szPost.Length) requestStream.Close() httpresponse = CType(httprequest.GetResponse(), _ HttpWebResponse) responsestream = httpresponse.GetResponseStream() bodyreader = New StreamReader(responsestream) bodytext = bodyreader.ReadToEnd() Return bodytext
End Function
This differs from the code to simply retrieve a Web page in that once the HttpWebRequest has been created, several parameters are set such that the request also includes the posted data. The chunked reader loop is also replaced with the ReadToEnd() method of StreamReader . This method may
be elegant, but it is not compatible with binary data. The three settings that need to be changed are the request method, con-
tent type, and content length. The request method is usually GET but now must be set to POST . The content type should be set to the MIME type application/x-www-form-urlencoded , although this is not strictly neces- sary. The content length is simply the length of the data being posted, including the variable names, and after URL encoding.
Chapter 4
102 4.2 HTTP
Figure 4.2
Visual Studio .NET, Add Reference dialog.
The data to be posted must then be sent to the server using the Write method on the request stream. Once the request has been created, it is sim- ply a matter of receiving the stream from the remote server and reading to the end of the stream.
Finally, we need namespaces for the HttpUtility and Encoding objects. You will need to make a reference to System.Web.dll by selecting Project→ → → → Add Reference, as shown in Figure 4.2.
C#
using System.Web; using System.Text; using System.IO; using System.Net;
VB.NET
Imports System.Web Imports System.Text Imports System.IO Imports System.Net
4.2 HTTP 103
Figure 4.3
HTTP client application with POST facility.
To test the application, run it through Visual Studio .NET, enter http:// localhost/postTest.aspx into the URL textbox, and add some other text into the POST textbox. When you press Capture, you will see that the posted text appears as part of the Web page (Figure 4.3).
Table 4.5 shows the significant members of HttpWebRequest .
Table 4.5 Significant members of HttpWebRequest .
Method or Property
Meaning
Accept Gets or sets the value of the Accept HTTP header. Returns String .
AllowAutoRedirect Gets or sets a Boolean value that indicates whether the request should follow redirection (3xx) responses.
ContentLength Gets or sets the Content-length HTTP header. ContentType
Gets or sets the value of the Content-type HTTP header.
CookieContainer Gets or sets the cookies associated with the request. May be invoked thus: CookieContainer.getCookies[“name”].ToS tring() .
Chapter 4
104 4.2 HTTP
Table 4.5 Significant members of HttpWebRequest (continued).
Method or Property
Meaning
Headers Gets a collection of strings that are contained in the HTTP header. May be invoked thus: Headers[“Content-Type”].ToString() .
Method Gets or sets the method for the request. Can be set to GET , HEAD , POST , PUT , DELETE , TRACE , or
OPTIONS .
Proxy Gets or sets proxy information for the request. Returns WebProxy .
Referer Gets or sets the value of the Referer HTTP header. Returns String .
RequestUri Gets the original URI of the request. Address is the URI after redirections. May be invoked thus: RequestURI.ToString() .
Timeout Gets or sets the time-out value. May be invoked thus Timeout=(int) new
TimeSpan(0,0,30).TotalMilliseconds . TransferEncoding
Gets or sets the value of the Transfer-encoding HTTP header. Returns String .
UserAgent Gets or sets the value of the User-agent HTTP header. Returns String .
GetResponse Returns a webResponse from an Internet resource. Its asynchronous variant is BeginGetResponse and
EndGetResponse .