SharpTools: HTTP GET, POST, uploading files and cookie/session authentication in C#
Downloads for the software described here are available on the downloads page.
Blimey. You'd think in the 21st century retrieving web pages and POSTing forms and file uploads in the .NET framework would be a quick and painless exercise. But apparently, this isn't the case, so here's a quick and dirty class library to do it for you.
(This code is part of a general tool library I developed called SharpTools, with lots of other features, but those haven't been released yet)
My basic problem was:
- Login to a web site by POSTing a username and password to a form
- Upload some files via POST to a second form after logging in
First I'll take you through how Microsoft wants you to do it, then I'll explain how my class library works.
How HTTP requests work in .NET: A Crash Course
Include the namespace System.Net in your code to access all the classes below.
First you create an HttpWebRequest object with the URL you want like this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(myUrl);
Then set the method, which for our purposes will either be GET or POST:
request.Method = "GET";
Submitting forms usually calls for using POST, fetching pages (with or without query parameters) usually calls for using GET.
If you're POSTing a form (without uploading files) you need to set the Content-Type HTTP header to let the web server know you're sending POST data in the request body, like this:
request.ContentType = "application/x-www-form-urlencoded";
For submitting forms via POST, throw the request body into a string, which takes the same format as a query string in a GET request, then encode it into a byte array:
string args = @"param1=value1¶m2=value2¶m3=value3"; byte[] dataToSend = Encoding.ASCII.GetBytes(args);
Sending the request is done automatically when you ask your request object to return a response. If you're sending a GET request, there is no request body so you can skip the following step. If you're sending a POST request, you need to transmit the request body as follows:
request.ContentLength = dataToSend.Length; Stream st = request.GetRequestStream(); st.Write(dataToSend, 0, dataToSend.Length); st.Close();
Note this will throw a WebException exception if there's a problem.
Now you can retrieve the response body as follows:
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader sr = new StreamReader(response.GetResponseStream()); string responseBodyText = sr.ReadToEnd(); sr.Close();
At this point, if all has gone well, responseBodyText will now contain the web page or response body of the request. Again, you'll get a WebException if there's a problem.
Getting the response code
Response codes like 200 (successful request or "OK"), 302 (redirection to another page or "Found"), 404 (page not found or "Not Found") indicate what happened when you made the request. You can access the response code by querying the property response.StatusCode.
Getting response headers
If you're looking for a particular header, for example the Location header of a 302 redirection, you can do so like this:
string locationHeader = response.GetResponseHeader("Location");
and so on for any other headers you'd like to access.
Preventing auto-redirection
By default, .NET will follow 302 redirections automatically. Sometimes you might not want this, for example if you POST to a login form whereby you'll be redirected to different pages depending on whether or not your login was successful. You might want to find out which page you're being sent to first, in which case you can disable auto-redirection like this:
request.AllowAutoRedirect = false;
Adding custom headers
Sometimes you'll want to add your own headers, for example to prevent caching. Here's how you can do that:
request.Headers.Add("Pragma", "no-cache");
where the first argument is the header name and the second argument is the header value.
HTTP 417 Expectation failed
Whoever wrote the HTTP library code at Microsoft had the genius (ahem) idea of not POSTing form data directly on the first request, but instead to tell the web server that a request is coming, get a 100 Continue header back, then send the actual data in a second request body. This breaks Apache, which is used by the majority of web sites. To fix this, you need to add this code before you make the request:
request.ServicePoint.Expect100Continue = false;
This property was added in .NET 2.0.
How to handle cookie/session-based authentication
In general, when you login to a web site via a login form, upon successful login the browser will be sent a cookie containing a unique login ID, which is then sent back to the site on all subsequent page requests to identify yourself as the logged in user. If you don't send the cookie back, you'll be treated as an anonymous (non-logged in) guest.
After a successful login therefore, you need to store the cookies you receive back from the site. This can be done with the following code:
CookieCollection cookies = response.Cookies;
Then you need to supply these cookies back to the web server in all subsequent requests like this:
request.CookieContainer = new CookieContainer(); foreach (Cookie c in cookies) request.CookieContainer.Add(c);
How do I upload files?
This is where it gets rather tricky. First of all, POSTed data which includes files has to be sent with a Content-Type of multipart/form-data, together with a so-called boundary parameter which separates each argument and file supplied in the request body into separate parts. After each part, the boundary parameter is given to signal the end of the part. The boundary parameter is also used at the start and (slightly modified) end of the entire request body.
Unlike with a regular POST request without files, each and every non-file argument must be supplied in its own part, not as a GET-style encoded string.
An example will illustrate the principle. Let's suppose our boundary parameter is "MyBoundary" (a very bad choice; the boundary should be something that won't appear in any of the arguments or file content). Let's also suppose we are sending a description of the file in a separate argument called desc and a title for it in title. The file argument itself will be called file.
First you'll set the Content-Type as follows:
request.ContentType = "multipart/form-data; boundary=MyBoundary";
Now you will need to manually create the request body, which will look exactly like this:
--MyBoundary Content-Disposition: form-data; name="title" Katy in Oslo --MyBoundary Content-Disposition: form-data; name="desc" This is a picture of me in Oslo last summer. --MyBoundary Content-Disposition: form-data; name="file"; filename="C:\Documents and Settings\Katy\Desktop\SomeFile.jpg" Content-Type: application/octet-stream <binary data of the file goes here> --MyBoundary--
The request body format is very strict and will fail unless you format it exactly as above. Specifically:
- Each boundary must start on a newline and be preceeded by two hyphens (
--). - There must be a Content-Disposition header for each argument.
- There must be a blank line between the headers for each part and the body.
- File arguments must have a Content-Type header, and the Content-Disposition header must include a
filenameparameter otherwise the web server will consider the file argument to have been left blank. - At the end of the request body, you must append two hyphens to the end of the last boundary.
Now you just encode the request body string and send it in the same manner as above for POSTing without files.
Summary
What a hassle eh? In summary:
- You have to create a new request object and start from scratch for every request.
- You have to encode the arguments or request body for every request.
- You have to remember to store and resend cookies before and after every request if you need to stay logged in.
- You have to remember to set the
Expect100Continueproperty for every request. - There is no standardised way of creating all three kinds of request, you have to manually produce the request body yourself depending on the type of request you want to make.
- You can't just send the request as text or get the response as text, you have to get the request and response streams and write/read from them, then close them afterwards, as appropriate.
- There's alot of error checking for exceptions you have to do which I haven't included above at all.
Pretty weak. Let's see if we can make it any easier.
My HTTP Library
I've created two classes, HTTPWorker to make requests simpler, and MIMEPayload to automatically create the request bodies when POSTing with files. You don't need to use this in your code though, HTTPWorker will create one automatically if you want to send files.
I won't document all the properties and methods here, because the source code includes XML documentation which you can compile if you like. There are also examples of logging in and POSTing files included, but I will illustrate how it works here.
Things to note about my class:
- You can re-use the object for many requests. In each case, you must set the
Urlproperty first (this sets up theExpect100ContinueandAllowAutoRedirectproperties of the HttpWebRequest object used internally), then theTypeproperty, which determines how the request body will be created. - Cookies will be auto-persisted unless you turn it off by setting
PersistCookiesto false, so logging in is now a fire-and-forget experience. - POST and POST-with-files requests are now handled the same. You can add arguments with
AddValueand files withAddFile. The request will be created according to theTypeproperty. - You can fetch the request and response objects at any time with the
RequestObjectandResponseObjectproperties if you need to query or set additional headers, change the auto-redirect flag etc. - You don't need to mess with streams. You can get the response text from the
ResponseTextproperty. The first time you use this after a request, it will open the response stream, read the response and cache it. On subsequent uses, it will just receive the response text from the cache.
Setting up
Do this once before any series of requests in your application. The object can persist for the lifetime of the application if you so wish.
HTTPWorker http = new HTTPWorker(); HttpWebResponse rsp = null;
GET a web page
http.Url = "http://yoursite.com/pageToFetch.html";
http.Type = HTTPRequestType.Get;
http.RequestObject.AllowAutoRedirect = false; // if required
try
{
rsp = http.SendRequest();
}
catch (WebException ex)
{
Console.WriteLine(ex.Message);
return;
}
string webPage = rsp.ResponseText;
POSTing a form
http.Url = "http://yoursite.com/login.php";
http.Type = HTTPRequestType.Post;
http.AddValue("username", username);
http.AddValue("password", password);
try
{
rsp = http.SendRequest();
}
catch (WebException ex)
{
Console.WriteLine(ex.Message);
return;
}
// You can now check for the response code with rsp.StatusCode to see what happened
If you posted a login form and it was successful, the cookie is now stored and will be used automatically on your next request.
POSTing a form with file uploads
This uses the example I gave above and creates the exact request body shown above, just with a different boundary (which is set automatically).
http.Url = "http://yoursite.com/uploadpage.php";
http.Type = HTTPRequestType.MultipartPost;
http.RequestObject.KeepAlive = true;
http.RequestObject.Headers.Add("Pragma", "no-cache");
http.AddValue("title", "Katy in Oslo");
http.AddValue("desc", "This is a picture of me in Oslo last summer.");
http.AddFile("file", @"C:\Documents and Settings\Katy\Desktop\SomeFile.jpg");
try
{
rsp = http.SendRequest();
}
catch (WebException ex)
{
Console.WriteLine(ex.Message);
return;
}
Checking if the request was successful
In most cases you'll probably need to parse the page to check that what you intended to do was actually successful. You can do this pretty easily with regular expressions in the System.Text.RegularExpressions namespace, or with basic status code and string functions like this:
if (rsp == null)
{
// The web server didn't return anything
}
if (rsp.StatusCode != HttpStatusCode.OK)
{
// There was an error
}
if (http.ResponseText.Contains("Login failed!"))
{
// The text 'Login failed!' was found on the form
errorText = Regex.Replace(http.ResponseText,
"^.*<h2>Login failed!</h2>.*<p>(?<error>.*)</p>.*$", "${error}", RegexOptions.Singleline);
}
The principle of this is fairly simple. The regex parses the entire web page as a single line (meaning that .* can span across newlines), looking for the error message, and captures it into a group called error. The entire web page content is then replaced with just the error message, which is stored in errorText. To make sure the entire web page is replaced, we must parse it all, which is done by ensuring ^.* appears at the beginning and .*$ appears at the end. These symbols match the start of the page plus any number of characters, and any number of characters plus the end of the page respectively.
Final words
I've now used this library in a couple of projects and it's made life alot simpler. I hope you find it useful too!
Printer-friendly version- 8581 reads
louboutin
ugg boots
christian louboutin
louboutin
christian louboutin
louboutin shoes
christian louboutin boots
lv handbags
mbt shoes
christian louboutin
jimmy choo
cheap jimmy choo
discount jimmy choo
jimmy choo sale
jimmy choo shoes
jimmy choo boots
Manolo Blahnik
cheap Manolo Blahnik
discount Manolo Blahnik
Manolo Blahnik sale
Manolo Blahnik shoes
Manolo Blahnik boots
Yves saint Laurent
cheap Yves saint Laurent
discount Yves saint Laurent
Yves saint Laurent sale
Yves saint Laurent pumps
Yves saint Laurent boots
Ed Hardy
cheap Ed Hardy
discount Ed Hardy
Ed Hardy sale
Ed Hardy boots
Balmain Shoes
cheap Balmain Shoes
discount Balmain Shoes
Balmain Shoes sale
Balmain boots
Alexander McQueen
cheap Alexander McQueen
discount Alexander McQueen
Alexander McQueen sale
Alexander McQueen shoes
Alexander McQueen pumps
gucci shoes
cheap Gucci shoes
discount gucci shoes
gucci Shoes sale
gucci shoes
UGG boots
cheap UGG boots
discount UGG boots
UGG boots sale
UGG australia
Tory Burch Shoes
cheap Tory Burch Shoes
discount Tory Burch Shoes
Tory Burch Shoes sale
Tory Burch Shoes
Bottega Veneta
cheap Bottega Veneta
discount Bottega Veneta
Bottega Veneta sale
Bottega Veneta
Lanvin Shoes
cheap Lanvin Shoes
discount Lanvin Shoes
Lanvin Shoes sale
Lanvin boots
Herve Leger Dress
cheap Herve Leger Dress
discount Herve Leger Dress
Herve Leger Dress sale
Herve Leger
MBT Shoes
cheap MBT Shoes
discount MBT Shoes
MBT Shoes
MBT Shoes
louboutin
ugg boots
christian louboutin
louboutin
christian louboutin
louboutin shoes
christian louboutin boots
lv handbags
mbt shoes
christian louboutin
jimmy choo
cheap jimmy choo
discount jimmy choo
jimmy choo sale
jimmy choo shoes
jimmy choo boots
Manolo Blahnik
cheap Manolo Blahnik
discount Manolo Blahnik
Manolo Blahnik sale
Manolo Blahnik shoes
Manolo Blahnik boots
Yves saint Laurent
cheap Yves saint Laurent
discount Yves saint Laurent
Yves saint Laurent sale
Yves saint Laurent pumps
Yves saint Laurent boots
Ed Hardy
cheap Ed Hardy
discount Ed Hardy
Ed Hardy sale
Ed Hardy boots
Balmain Shoes
cheap Balmain Shoes
discount Balmain Shoes
Balmain Shoes sale
Balmain boots
Alexander McQueen
cheap Alexander McQueen
discount Alexander McQueen
Alexander McQueen sale
Alexander McQueen shoes
Alexander McQueen pumps
gucci shoes
cheap Gucci shoes
discount gucci shoes
gucci Shoes sale
gucci shoes
UGG boots
cheap UGG boots
discount UGG boots
UGG boots sale
UGG australia
Tory Burch Shoes
cheap Tory Burch Shoes
discount Tory Burch Shoes
Tory Burch Shoes sale
Tory Burch Shoes
Bottega Veneta
cheap Bottega Veneta
discount Bottega Veneta
Bottega Veneta sale
Bottega Veneta
Lanvin Shoes
cheap Lanvin Shoes
discount Lanvin Shoes
Lanvin Shoes sale
Lanvin boots
Herve Leger Dress
cheap Herve Leger Dress
discount Herve Leger Dress
Herve Leger Dress sale
Herve Leger
MBT Shoes
cheap MBT Shoes
discount MBT Shoes
MBT Shoes
MBT Shoes
jeans
Shop online for the latest trends in denim and fashion of the True Religion JeansTrue Religion Jeans,Seven jeans. This Seven for mankind is the new sexy look for Summer 2009. You can raid your boyfriend's closet, or you can get yourown!Free shipping with fast delivery now.Hurry up.
Looking For discountchanel
Looking For discountchanel replica
Beautifulgucci handbags for sale
油墨
Balenciagafor sale
Looking For discountchanel
If you want to buylouis vuitton
丝印器材
Looking For discountchanel handbags
Beautifulgucci for sale
The store online sells theBalenciaga bags
different kinds oflouis vuitton for cheap
网版烤箱
ghd straighteners for Cheap Wholesale
If you want to buylouis vuitton bag
different kinds oflouis vuitton handbag for cheap
replica louis vuitton bag for for Cheap Wholesale
ghd very cheap
china Wholesale
ghd hair straighteners for Cheap Wholesale
移印器材
replica louis vuitton bag for Cheap Wholesale
album evoke
cialis drug W e _ a r e _ v e r y _ s o r r y _ f o r _ a n y _ i n c o n v i n i e n c e _ c a u s e d _ t o _ y o u _ b y _ o u r _ m e s s a g e . W e _ w e r e _ s e e k i n g _ f o r _ o l d _ " n o b o d y ' s " _ w e b s i t e s . _ I f _ i t ' s _ a _ m i s t a k e _ a n d _ w e _ d i s t u r b e d _ y o u , _ p l e a s e _ d e l e t e _ o u r _ m e s s a g e , _ a n d _ w e ' l l _ n e v e r _ r e t u r n _ h e r e . O n e _ m o r e _ t i m e , _ s o r r y _ f o r _ a n y _ t r o u b l e s _ t h a t _ w e ' v e _ c a u s e d _ b y _ o u r _ a c t i v i t y .
大阪 高収入求人
大阪 デリヘル
大阪 高収入求人
中古コピー機
大阪 デリヘル
大阪 デリヘル
大阪 デリヘル
日本語ラップ
日本語ラップ
MIX CD 通販
中古コピー機
中古コピー機
漫画 おすすめ マンガ
cheap ghd
Truely a nice blog and thanks for your great work. By the way,welcom to our websites:www.fashionhairfu.com . We provide cheap hair straighters, including the
ghd precious gift set
ghd pretty in pink
ghd radiance set
ghd rare styler
ghd iv gold styler
ghd iv kiss styler
ghd iv black styler
ghd iv pink styler
ghd iv dark styler
ghd iv pure styler
ghd iv purple styler
ghd iv styling
ghd iv mini styler
babyliss straightening
instyler curling irons
chi pink flat iron
chi turbo 2 big flat iron
chi black flat iron
, the limited edition ghd precious gift set , cheap ghd pretty in pinkand so on. Nothing would be more suitable than these on our sites ghd flat iron. Wholesale and retail are both acceptable to us. Welcome to our site and free to look! Thank you and wish you a nice day. Good Luck!All of the product are popular around the world. In addition,ghd dark styler
are also very popular.our products also have a corresponding discount activities,Do NOT miss it! Wholesale and retail are both acceptable to us. Welcome to our site and free to look! Thank you and wish you a nice day. Good Luck!
cheap ghd
Truely a nice blog and thanks for your great work. By the way,welcom to our websites:www.fashionhairfu.com . We provide cheap hair straighters, including the
ghd precious gift set
ghd pretty in pink
ghd radiance set
ghd rare styler
ghd iv gold styler
ghd iv kiss styler
ghd iv black styler
ghd iv pink styler
ghd iv dark styler
ghd iv pure styler
ghd iv purple styler
ghd iv styling
ghd iv mini styler
babyliss straightening
instyler curling irons
chi pink flat iron
chi turbo 2 big flat iron
chi black flat iron
, the limited edition ghd precious gift set , cheap ghd pretty in pinkand so on. Nothing would be more suitable than these on our sites ghd flat iron. Wholesale and retail are both acceptable to us. Welcome to our site and free to look! Thank you and wish you a nice day. Good Luck!All of the product are popular around the world. In addition,ghd dark styler
are also very popular.our products also have a corresponding discount activities,Do NOT miss it! Wholesale and retail are both acceptable to us. Welcome to our site and free to look! Thank you and wish you a nice day. Good Luck!
cheap uggs online nike
cheap uggs online
nike outlet
ugg outlet
ugg boots
ugg boots
ugg stores
Do you know [url=http://www.buywydgold.com]wyd gold[/url]?
Do you know [url=http://www.buywydgold.com]wyd gold[/url]?if you play the online game,you will know [url=http://www.buywydgold.com]buy wyd gold[/url]is the game gold. In the game,if you had more [url=http://www.buywydgold.com]With Your Destiny gold[/url],you will had a tall level. But if you want [url=http://www.buywydgold.com]buy With Your Destiny gold[/url],you can come here and spend a little money to bought [url=http://www.buywydgold.com]cheap wyd gold[/url].Quickly come here
really nice post, just wish
really nice post, just wish you to check out timberland boots uk, like timberlands uk.
nike outlet nike outlet uggs
nike outlet
nike outlet
uggs sale
cheap uggs
basketball shoes
basketball shoes
As see too By default; .NET
As see too By default; .NET will follow 302 redirections automatically. Sometimes you might not want this, for example if you POST to a login form whereby you'll be redirected to different pages depending on whether or not your login was successful that also You might want to find out which page you're being sent to first, in which case you can disable auto-redirection like this:
___________________
Glamour Galleries
Excellent post,thanks for
Excellent post,thanks for sharing,looking for more.welcome to my page!
Gucci
Gucci shop
Gucci bags
Gucci shoes
Gucci ON sale
Gucci Belts
Gucci small accessories
Gucci hats & scarves
Gucci wallets
Gucci Handbags
Women Gucci shoes
Men Gucci shoes
Thanks!
明石焼き ホームページ制作 駄菓子 いか焼 イギリス車
明石焼き ホームページ制作 駄菓子 いか焼 イギリス車 囲碁教室 居合道 工芸品 時計 産婦人科 美容整形 CFD 保険 リフォーム 結婚相談所 エステ 婚活 レンタルサーバー 探偵 税理士 不動産会社 看護師求人 インプラント システム開発 求人 SEO対策 風俗 風俗求人 FX 人気 転職 歯医者 自動車保険 高収入 証券会社 高校 ラーメン クレジットカード 太陽光発電 コスメ オンラインゲーム 企業 化粧品 就職 大学 ホームページ制作 オール電化 ホテル 歯医者 引越 歯医者 エステ 口コミ 探偵 結婚相談所 美容整形 エステ 病院 化粧品 コスメ 産婦人科 ダイエット 新築 静岡 原宿 ウェディング 広島 新築 広島 土地 広島 住宅 岡山 マンション 結婚情報サービス
栃木県 賃貸マンション 栃木県 奈良県 岐阜県 宮城県
栃木県 賃貸マンション 栃木県 奈良県 岐阜県 宮城県 群馬県 長野県 不動産賃貸 福島県 沖縄県 宮崎県 熊本県 鹿児島県 大分県 投資 山梨県 滋賀県 新潟県 新築マンション 石川県 富山県 和歌山 リフォーム 高知県 インテリア セクシーランジ ェリー 化粧品 外車 結婚指輪 ブランド品 滋賀県 アウトレット アメリカ アロマ あんみつ 海外旅行 甘味処 編物教室 足裏療法 収益物件 賃貸住宅 イギリス料理 コーチング 育児相談 家具 個人輸入 鯉 CDショップ コテージ ゴルフ ゴルフ会員権 ファッション 下着 SEO対策 アイスクリーム アウトドア アクセサリー 結婚式
葬儀場 質屋 リサイクルショップ 大学受験 グループホーム
葬儀場 質屋 リサイクルショップ 大学受験 グループホーム ブランド品 建設会社 動物病院 中学受験 税理士 株取引 レーシック 専門学校 派遣 携帯 ラブコスメ 予備校 小児科 旅行 旅館 ケータリング ホテル サイト売買 インプラント 弁護士 ナイキ わけあり ズワイガニ 通販 無添加化粧品 松山 土地 高知 土地 高松 土地 ナノコラーゲン アダルトグッズ通販 ダイエット茶 ペアリング通販 結婚相談所 インプラント 産婦人科 インプラント 病院 税理士 歯医者 自動車保険 クレジットカード 比較 お見合いパーティー 結婚式場 ケータリング 不動産会社 占い 探偵 学習塾 ネイルサロン 英会話 太陽光発電 老人ホーム 家庭教師 写真館 予備校 バイト 温泉 株 引越 大学受験 美容院 レーシック 中古車 質屋 小児科 ラブホテル
脱毛 永久脱毛 英会話 眼科 受験 学習塾 会計士
脱毛 永久脱毛 英会話 眼科 受験 学習塾 会計士 行政書士 法人設立 公認会計士 オフィス移転 結婚相談所 結婚式 結婚式場 婚活セミナー お見合い パーティー 出会い お見合いパーティー パーティー パーティードレス パーティー 出会いパーティー ウェディング ウエディング 結婚指輪 税理士 オークション 美容外科 美容院 探偵 ホテル 口腔外科 インプラント治療 広島インプラント インプラント インプラント大阪 インプラント 費用 インプラント東京 インプラント歯科 カタログ販売 家庭教師 幼稚園 弁護士 司法書士 受験 ラブホテル 学習塾 下着 バイク 介護施設 自転車 パーティー リフォーム カラオケボックス 設計事務所 ランジェリー 宗教団体 小児歯科 デイサービス
High quality fake rolex
High quality fake rolex paypal of well known brands - Jacob & Co, TAG Heuer, Cartier, Panerai and much more. *If you want to buy replica watches paypal, you have come to the right place! We are leading supplier of all kinds of strongfake watches. The leading name in luxury watches, replica rolex paypal has been the pre-eminent symbol of performance and prestige for over a century. Replica Swiss Rolex men's and ladies' watches.
Post new comment