HttpWebRequest详解

Determining Whether the Device Is Connected

 

Most network applications need to know whether the device is currently connected to the network. A well-designed mobile application allows the user to make use of it even if the device isn’t connected. For example, if the device has lost wireless connectivity, it should be able to operate using data cached on the device, and then possibly re-sync with a server when network connectivity is regained.

There is no class in the .NET Compact Framework that raises events to inform an application when connection to the network is lost and regained. Instead, you must code with this eventuality in mind and make sure your application is tolerant of network outages. You might need to write code that polls for a network resource to determine when the device has network connectivity.
For example, if your application uses XML Web services, you might need to connect to the service to upload data changes and download data to the device when a network connection is available. In your application, you should write a method that uses the WebResponse class to send an HTTP GET request to a valid URL on the server where the XML Web service is located. If the HttpWebResponse.StatusCode property in the response equals HttpStatusCode.OK, connectivity to the server is confirmed. You should call this method from a TimerEvent of a System.Threading.Timer instance to poll the server at intervals; when the method succeeds, the application knows that it can make a successful HTTP connection to the server, so the interaction with the XML Web service or access to other network resources can proceed.

Understanding WebRequest and WebResponse Basics

The most important classes in the System.Net namespace are the WebRequest and WebResponse classes, which are abstract classes.

 

using System.Net;
using System.IO;

    WebRequest req = WebRequest.Create(uri);
    WebResponse res = req.GetResponse();    // GetResponse blocks until the response arrives
    Stream ReceiveStream = res.GetResponseStream();    // Read the stream into a string
    StreamReader sr = new StreamReader( ReceiveStream );
    string resultstring = sr.ReadToEnd();

 

Fetching a Resource Using HTTP

If the scheme of the URI is http:// or https://, the Create method returns an instance of the HttpWebRequest class. The GetResponse method of this instance makes a request to the resource and returns an HttpWebResponse instance that contains the response.

 


using System;
using System.IO;
using System.Net;

namespace NETCFDevelopersReference
{
    
class HttpGetSample
    
{
        
/// <summary>
        
/// The main entry point for the application.
        
/// </summary>

        static void Main(string[] args)
        
{
            HttpGetSample thisclass 
= new HttpGetSample();
            thisclass.getPage(
"target URL here"); // <-- EDIT THIS!
        }


        
public void getPage(String url) 
        
{
            WebResponse result 
= null;

            
try 
            
{
                WebRequest req 
= WebRequest.Create(url);
                result 
= req.GetResponse();
                Stream ReceiveStream 
= result.GetResponseStream();

                
//read the stream into a string
                StreamReader sr = new StreamReader( ReceiveStream );
                
string resultstring = sr.ReadToEnd();

                Console.WriteLine(
"\r\nResponse stream received");
                Console.WriteLine(resultstring);
            }
 
            
catch(Exception exp) 
            
{
                Console.Write(
"\r\nRequest failed. Reason:");
                Console.WriteLine(exp.Message);
            }
 
            
finally 
            
{
                
if ( result != null ) 
                
{
                    result.Close();
                }

            }


            Console.WriteLine(
"\r\nPress Enter to exit.");
            Console.ReadLine();
        }
    
    }

}


The Finally block ensures that the WebResponse object is closed, regardless of the success or failure of the program. This is important to ensure that network resources are not wasted.

Handling Errors

You get an exception of type UriFormatException when the URI cannot be parsed or an exception of type WebException for other errors. The Status property of WebException returns a value from the WebExceptionStatus enumeration. If Status is WebExceptionStatus.ProtocolError, the exception is a result of an HTTP protocol error. You can then access the WebException.Response property, which returns an HttpWebResponse object containing the response from the server. Use the HttpWebResponse.StatusCode property to find out the HTTP status code the server sent back, and use HttpWebResponse.StatusDescription to obtain the description string that corresponds to that status code.

Working with HTTP Headers


The HttpWebRequest class allows you to control the HTTP headers sent with your request, which you do by setting properties or by executing methods of the class.

HTTP Headers Sent

HTTP Header

Set By

Accept

HttpWebRequest.Accept property

Connection

HttpWebRequest.Connection and HttpWebRequest.KeepAlive properties

Content-Length

HttpWebRequest.ContentLength property

Expect

HttpWebRequest.Expect property

Date

Set to the current system date

Host

Not set

If-Modified-Since

HttpWebRequest.IfModifiedSince property

Range

HttpWebRequest.AddRange method

Referer

HttpWebRequest.Referer property

Transfer-Encoding

HttpWebRequest.TransferEncoding property (the HttpWeb­Request.SendChunked property must be true)

User-Agent

HttpWebRequest.UserAgent property

The HttpWebResponse instance exposes HTTP headers as properties in a similar way.
 

HTTP Headers Received

HTTP Header

Read By

Content-Encoding

HttpWebResponse.ContentEncoding property

Content-Length

HttpWebResponse.ContentLength property

Content-Type

HttpWebResponse.ContentType property

Length

HttpWebResponse.Length property

Server

HttpWebResponse.Server property


Both classes also have a Headers property that exposes HTTP headers as a System.Net.WebHeaderCollection instance. For example, instead of using the UserAgent property, you can add the User-Agent header using the following code:

 

HttpWebRequest req = (HttpWebRequest) WebRequest.Create(uri);
req.Headers.Add(
"User-Agent""dotNETCF Test Program");

HttpWebResponse res 
= (HttpWebResponse) req.GetResponse();
String server 
= res.Headers["Server"];

 

Network Transfer Encoding

All data transferred over the network is encoded. The Windows CE operating system uses Unicode to represent characters, but this requires at least 2 bytes to represent any character, which is not as efficient as the U.S. ASCII character set, which requires only one byte per character. But ASCII represents only commonly used characters in Western alphabets, so it is unusable in languages requiring other characters, such as European languages, Chinese, Japanese, or Arabic.

The compromise solution is to use character encodings. The most common of these is UTF-8, which is a variable-length multibyte encoding requiring a single byte for 7-bit characters that are in the U.S. ASCII character set and 2 bytes for characters outside it. This results in efficient encodings for Western alphabets and the flexibility to handle non-Latin characters.

The default encoding assumed by the HttpWebRequest and HttpWebResponse classes is UTF-8

You can determine the character set encoding of a response by getting the HttpWebResponse.CharacterSet property. However, beware, there is a trick to this! You must set the MediaType property on the request; otherwise, the CharacterSet property on the HttpWebResponse will be blank. Even then, CharacterSet will only return the character set encoding used if the first part of the Content-Type header returned with the response (which is the media type) matches the value you set in the MediaType property of the request.

For example, if you set HttpWebRequest.MediaType to “text/html” before calling HttpWeb­Request.GetResponse, and the Content-Type header returned with the response is “text/html; charset=utf-8”, the HttpWebResponse.CharacterSet property will contain the name of the character set encoding (“utf-8”) because the “text/html” media type sent in the first part of the Content-Type header matches the value set in HttpWebRequest.MediaType. If the media types differ, HttpWeb­Response.CharacterSet is a null string.

 

 


 HttpWebRequest req = (HttpWebRequest) WebRequest.Create(url);
    
// You MUST set the MediaType property on the request, otherwise
    
// the CharacterSet property on the HttpWebResponse object will be
    
// blank.
    req.MediaType = "text/html";

    HttpWebResponse result 
= (HttpWebResponse) req.GetResponse();

    
// Note that the HttpWebResponse.ContentType property always
    
// returns the Content-Type header, which will be something like
    
// "text/html; charset=utf-8"
    string contenttype = result.ContentType;

    
// Character set encoding may be something like ISO-10646-UCS-2, 
    
// or UTF-8, us-ascii etc
    string charsetencoding = result.CharacterSet

    
//read the stream using the decoder
    Stream ReceiveStream = result.GetResponseStream();
    Encoding encode 
= System.Text.Encoding.GetEncoding(charsetencoding);
    StreamReader sr 
= new StreamReader( ReceiveStream, encode );

 

Using HTTP GET Query String

In the full .NET Framework, the System.Web.HttpUtility class provides methods to encode and decode URL-encoded data, but this class is not supported in the .NET Compact Framework. You must write your own code to handle URL encoding, such as the example code shown here:

 


using System;
using System.IO;

namespace NETCFDevelopersReference
{
    
/// <summary>
    
/// Replacement for HttpUtility.UrlEncode
    
/// </summary>
    public class HttpUtility
    {
        
public static string UrlEncode(string instring)
        {
            StringReader strRdr 
= new StringReader(instring);
            StringWriter strWtr 
= new StringWriter();
            
int charValue = strRdr.Read();
            
while (charValue != -1)
            {
                
if (((charValue >= 48&& (charValue <= 57)) // 0-9
                    ││((charValue >= 65&& (charValue <= 90)) // A-Z
                    ││((charValue >= 97&& (charValue <= 122))) // a-z
                    strWtr.Write((char) charValue);
                
else if (charValue == 32)    // Space
                    strWtr.Write('+');
                
else 
                    strWtr.Write(
"%{0:x2}", charValue);

                charValue 
= strRdr.Read();
            }

            
return strWtr.ToString();
        }
    }
}

 


Using HTTP POST

To use POST, just set the HttpWebRequest.Method property to “POST” and then proceed as for GET. A typical HTML page shown in a Web browser posts data as key=value pairs, with the data URL-encoded, so your application must format the data in that way if that is what the Web server application expects. If you are simply posting application content or XML, just post it as is.

 


    public void doPost(String url, String payload) 
    {
        WebRequest req 
= WebRequest.Create(url);
        req.Method 
= "POST";
        req.ContentType 
= "text/plain; charset=utf-8";

        
// Encode the data
        byte[] encodedBytes = Encoding.UTF8.GetBytes(payload);
        req.ContentLength 
= encodedBytes.Length;

        
// Write encoded data into request stream
        Stream requestStream = req.GetRequestStream();
        requestStream.Write(encodedBytes, 
0, encodedBytes.Length);
        requestStream.Close();

        WebResponse result 
= req.GetResponse();
        
    }

 

Alternatives to Cookies for Session State Support

The .NET Compact Framework implementation of the HttpWebResponse class does not support the Cookies property found in the full .NET Framework implementation. 

If you are using an ASP.NET application on the server, you can utilize the ASP.NET support for cookieless clients to track your smart device applications session. You enable this by setting cookieless to “true” in the sessionState configuration in the ASP.NET application’s Web.Config 

ASP.NET uses a munged URL to track sessions for cookieless clients, meaning it embeds a session ID into the response URI. For example, if your application makes a request to http://myserver/myserverapp.aspx, the response URI that returns to the client is actually something like http://myserver/(1en4l345qq203lr2f0h4xt45)/myserverapp.aspx. To the client, it looks like a server-side redirect. In the client application, this response URI is in the HttpWebResponse.ResponseUri property, so the client application need only use this URI for subsequent requests for the server application to be able to identify those requests as coming from that particular client.

Authenticating Requests with the NetworkCredential Class

 

 WebRequest req = WebRequest.Create(url);
   NetworkCredential creds 
= 
       
new NetworkCredential("andy""pA55w0rd""");
   req.Credentials 
= creds;
   WebResponse result 
= req.GetResponse();

 

Making Network Requests via a Proxy Server

 

   //  Pass Proxy string and bypass local machine
   WebProxy myProxy = new WebProxy(
     
"http://myproxyserver.mine.com:8080"true);
   
   
// If  this proxy requires authentication
   myProxy.Credentials = 
      
new NetworkCredential("loginname","password");
   
   Request.Proxy 
= myProxy;

 

Asynchronous Web Requests

 


using System;
using System.IO;
using System.Threading;

namespace NETCFDevelopersReference
{
    
class HttpGetAsyncSample 
    
{
        
public static void Main(string[] args) 
        
{
            HttpGetAsyncSample thisclass 
= new HttpGetAsyncSample();
            thisclass.Run();
        }


        
private bool isComplete;

        
public void Run()
        
{
            Console.WriteLine();
            Console.WriteLine(
"Test Program makes HTTP AsyncGet"
                
+ " to http://www.gotdotnet.com/team/netcf");
            Console.WriteLine(
"Press Enter to continue");
            Console.ReadLine();

            GetHttpAsync callit 
= new GetHttpAsync();
            
// Wire up to handle the complete event
            callit.GetComplete += new 
                GetHttpAsync.GetCompleteHandler(
this.GetCompleteHandler);
            
// Set the flag we will check for completion
            isComplete = false;

            Console.WriteLine(
"Making async call");
            callit.getPage(
"http://www.gotdotnet.com/team/netcf");

            Console.WriteLine(
"Main thread writes these dots, "
                
+ "while async fetch proceeds");
            Console.WriteLine(
"in secondary thread");
            
int count = 0;
            
while (!isComplete)
            
{
                Console.Write(
".");
                
if (++count == 80) Console.WriteLine();
                Thread.Sleep(
500); // Sleep for half a second
            }

            Console.WriteLine(
"\r\nResponse Received");
            Console.WriteLine(
"Press Enter to exit");
            Console.ReadLine();

            
return;
        }


        
protected void GetCompleteHandler()
        
{
            
// Event handler for get complete
            isComplete = true;
        }

    }

}


 


using System;
using System.Net;
using System.IO;
using System.Text;

namespace NETCFDevelopersReference
{
    
// The RequestState class is used to pass data
    
// across async calls
    public class RequestState
    
{
        
public HttpWebRequest Request;

        
public RequestState()
        
{
            Request 
= null;
        }

    }


    
/// <summary>
    
/// Class makes asynchronous HTTP Get to remote URL
    
/// </summary>

    public class GetHttpAsync
    
{
        
public delegate void GetCompleteHandler();
        
public event GetCompleteHandler GetComplete;

        
public void getPage(String url) 
        
{
            
try 
            
{
                HttpWebRequest req 
= 
                    (HttpWebRequest) WebRequest.Create(url);
                
// Create the state object
                RequestState rs = new RequestState();

                
// Add the request into the state 
                
// so it can be passed around
                rs.Request = req;

                
// Issue the async request
                req.BeginGetResponse(
                    
new AsyncCallback(this.ResponseCallback), rs);
            }

            
catch(Exception exp) 
            
{
                Console.WriteLine(
"\r\nRequest failed. Reason:");
                
while (exp != null)
                
{
                    Console.WriteLine(exp.Message);
                    exp 
= exp.InnerException;
                }

            }
 
        }


        
private void ResponseCallback(IAsyncResult ar)
        
{
            
// Get the RequestState object from the async result
            RequestState rs = (RequestState) ar.AsyncState;

            
// Get the HttpWebRequest from RequestState
            HttpWebRequest req = rs.Request;

            
// Get the HttpWebResponse object
            HttpWebResponse resp = 
                (HttpWebResponse) req.EndGetResponse(ar);

            
// Read data from the response stream
            Stream responseStream = resp.GetResponseStream();
            StreamReader sr 
= 
                
new StreamReader( responseStream, Encoding.UTF8);
            
string strContent = sr.ReadToEnd();

            
// Write out the first 512 characters
            Console.WriteLine("Length: {0}", strContent.Length);
            Console.WriteLine(strContent.Substring(
0
                strContent.Length 
< 512 ? strContent.Length : 512));

            
// Raise the completion event 
            GetComplete();

            
// Close down the response stream
            responseStream.Close();
        }

    }

}

 

 

posted @ 2008-11-14 15:34  小y  阅读(57239)  评论(6编辑  收藏  举报