14 Ağustos 2007 Salı

C#'ta Otomatik Web Form Gönderimi - Form Submitting

Hakkında yazılarımı girmeye vaktim olmasa da halen devam etmekte olan Microsoft Yaz Okulu 2007 eğitimlerindeyim. Bu eğitimlerde tanıştığım İTÜ Bilgisayar Mühendisliğinden arkadaşım Hasibe Göçülü(Blog) ile beraber onun bitirme tezindeki bir ihtiyacı gidermeye çalıştık. Bunula ilgili tecrübelerimi aktaracağım... Sorun tam olarak şöyle: Elimizde yaklaşık 1000 tane Protein dizilimin bulunuyor. Bu dizilimlerin her birinin http://jafa.burnham.org/newSession.html adlı sitedeki bir forma gönderilip yaklaşık 5 dak sonra sayfaya gelen(30 sn'de bir otomatik sayfa yenileniyor.) XML cevaplarının linkinin yakalanması ve indirilmesi gerekliliğiydi.

[more]

Çözüm için öncelikle Windows Forms projesinde bir adet WebBrowser bileşeni atmayla başladık. Bileşendeki HTML'in içine sonradan gömemeceğimiz bir script tagı ve buton sayesinde DOM üzerinden belli field'leri doldurmayı ve formu 'Submit' etmeyi planlıyorduk. Amacımız muhtemel 'Cookie', 'Session' gibi ayrıntıların hazır olarak bizi ilgilendirmeden bileşeni yazmaktı. Harici bir .js dosyasını yükleyip içinde bulunan metod yardımıyla forma submit komutunu vermemize rağmen sistem bize cevap vermedi. Ardından sistemin ayrıntılarına inmeye karar verdik. Öncelikle Ethereal adlı 'Network Sniffer' programıyla form submit edilirken hangi verilerin gönderildiğini yakaladık. Ardından C#'ın içinde System.Net namespace'i altında bulunan HttpWebRequest ve HttpWebresponse nesenlerini kullanmaya kara verdik(Http protokolünün implementasyonu için kullanılacak temel nesnelerdir). Ancak işler tahmin ettiğimiz  kadar kolay olmadı. Webbrowser bileşeni ile sayfayı açtığımızda bir adet cookie oluşuyordu. Bunu Http Header'ları arasına gömmüş olsak da sistem çalışmadı. Bir ayrıntı daha olduğunu anladık.(Bu arada cookie server'dan gelen bir 'Set-Cookie' komutuyla çalışmak yerine 'http://www.google-analytics.com/urchin.js' şeklinde bir adresten çektiği javascript dosyası ile oluşturuyordu. Mecburen de bu javascirpt'in derlenmesi ve cookie'nin oluşması gerekiyordu. Bu yüzden webbrowser bileşeni üzerinden çalışmaya devam ettik) Hasibe Content-Type header'inin yanında bulunan boundary ile başlayan bir satırdaki rakam ile gönderilen veride her satırda bulunan rakamın aynı olduğunu farketti. Sonuç başarılıydı. Karşı tarafatan beklediğimiz zaten sadece bir querystring idi. Bunu da yakalamış olduk Ethereal ile yakalanan veri yaklaşık şöyleydi. TCP       Kodları merak edenleriniz oldu tabi... Aşağıda...  

HttpWebRequest hWebReq = (HttpWebRequest)HttpWebRequest.Create(http://jafa.burnham.org/newSession.html);

HttpWebResponse hWebResp;

hWebReq.Method ="POST";

hWebReq.Referer =http://jafa.burnham.org/newSession.html;

//7d714.. şeklinde bilgileri de içeren yukarda belirtilen dosya, formun submit edilme anında ethereal ile yakalanmış

byte[] bf = File.ReadAllBytes(@"C:\myReq.txt");

hWebReq.ContentLength = bf.Length;

hWebReq.ContentType = "multipart/form-data; boundary=---------------------------7d7148ee0142";// Son Bulunan Nokta

hWebReq.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, */*";

hWebReq.Headers.Add("Cookie", webBrowser1.Document.Cookie);

hWebReq.GetRequestStream().Write(bf, 0, bf.Length);

hWebResp = (HttpWebResponse)hWebReq.GetResponse();

Stream str = hWebResp.GetResponseStream();

byte[] buf = new byte[20000];

//İlk oluşturmada string nesnesinin bir sorunu vardı; tüm bilgileri koyamadık; bu yüzden multiline bir textBox'ın içerisine 2 defada veriyi bastık, sonra geri aldık. O yüzden 2 defa tekrarlanıyor.str.Read(buf, 0, buf.Length);

str.Flush();

textBox1.Text = Encoding.ASCII.GetString(buf);

buf.Initialize();

str.Read(buf, 0, buf.Length);

textBox1.Text += Encoding.ASCII.GetString(buf);

string strPage = textBox1.Text;

string substrP = strPage.Substring(strPage.IndexOf("/result.html?ID="),"/result.html?ID=d398f118d3100146de4252289e68432a".Length );

substrPage = substrP.Substring("/result.html?ID=".Length, 32);

textBox2.Text = substrPage; 

string strur = "http://jafa.burnham.org/result.html?ID=" + substrPage;

webBrowser2.AllowNavigation = true;

webBrowser2.Navigate(strur);