February 7, 2006
Posting to a web page from a WinForms app
Sending an image to FogBugz is a two-step dance. First you send the image and FogBugz sends back the image index. Then you launch the FogBugz page you want to see, passing the image index in the querystring.
To send the image to FogBugz, you encode the image in a base64 string and then POST it to screenshot.asp (or to default.asp with the querystring parameter pg=pgSubmitScreenshot…this is what I did and what the FogBugz Screenshot tool does). I tried two different ways of posting the data COM automation and a .NET WebRequest.
The advantage of COM automation was that it was relatively few lines of code and the IE COM object would parse the results for me. Basically the code was something like this (with all the messy parts removed):
ie.Navigate(thePage)
index = ie.getElementById("ixscreenshot").InnerText
The disadvantage was the it requierd Internet Explorer, I had to add code to wait while the response was being read, and it used a bunch of late binding. I’m sure I could find the class definitions somewhere so that I could get the methods to show up in Intellisense, but it would still feel clumsy.
The advantage of the .NET WebRequest object is that it does not use IE and there is no waiting around in the code. Just build the request, get the response and ReadToEnd. Then scan the results for the index. Another advantage of using the WebRequest is reduced network traffic…albeit trivial. With COM automation, IE will dutifully download all the images and javascript that are on the page even though I only want the text. With the WebRequest, I just get the text and go. Here’s the full code:
private static int GetImageIndex(System.Drawing.Image image)
{
if (null == image) throw new ArgumentNullException("image");
string tagstart = "";
string tagend = "";
int index = -1;
System.IO.MemoryStream stream = new System.IO.MemoryStream();
image.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
string base64 = Convert.ToBase64String(stream.ToArray());
string postdata = "pg=pgSubmitScreenshot&fSaveOnly=1&cImageFragments=1&base64png1=";
postdata += System.Web.HttpUtility.UrlEncode(base64);
StreamWriter requestWriter = null;
HttpWebResponse response = null;
Stream responseStream = null;
StreamReader responseReader = null;
try
{
HttpWebRequest request;
Uri requestUri = new Uri(Config.ServerURL + "default.asp");
request = ((HttpWebRequest)(WebRequest.Create(requestUri)));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postdata.Length;
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(request.Address, RetrieveIECookiesForUrl(request.Address));
request.Proxy = WebProxy.GetDefaultProxy();
Stream requestStream = request.GetRequestStream();
requestWriter = new StreamWriter(request.GetRequestStream());
requestWriter.Write(postdata);
requestWriter.Close();
response = ((HttpWebResponse)(request.GetResponse()));
if (response.StatusCode == HttpStatusCode.OK)
{
responseStream = response.GetResponseStream();
responseReader = new StreamReader(responseStream);
string responseString = responseReader.ReadToEnd().ToLower();
if (responseString.IndexOf(tagstart) > -1)
{
int startIndex = responseString.IndexOf(tagstart) + tagstart.Length;
int stopIndex = responseString.IndexOf(tagend, startIndex);
index = Convert.ToInt32(responseString.Substring(startIndex, stopIndex - startIndex));
}
}
}
catch (System.UriFormatException ex)
{
MessageBox.Show("The FogBugz server URL is giving .NET fits (the url is '"
+ Config.ServerURL + "' and .NET says '" + ex.Message
+ "') . You can edit the server URL from the Preview. Select Show Preview as an option and then click on the URL.");
}
catch (Exception ex)
{
MessageBox.Show("GetImageIndex failed: " + ex.ToString());
}
finally
{
if (null != responseReader) responseReader.Close();
if (null != responseStream) responseStream.Close();
if (null != response) response.Close();
if (null != requestWriter) requestWriter.Close();
}
return index;
}
You might think CookieContainer should load the cookies for you, but it will not. The CookieContainer is a way to manipulate the cookies that the site sends back. It will not load persistent cookies for the initial request.
The huge disadvantage of using WebRequest is that it does not send any cookies unless you add them. Without the cookies, FogBugz does not know who you are and redirects the WebRequest to the Login page. Which is kind of pointless since the page is being parsed by code. The trick is to load the cookies for the web site into the WebRequest. Unfortunately there is no .NET method to do this.
That's what RetrieveIECookiesForUrl does, and that is what I'll write about next time.
This site looks much better in a browser that supports current web standards, but it is accessible to any browser.
Download one now
Some parts of this site will not work effectively on this older browser.
Please consider
updating your browser