Malisa Ncube - .NET Delights

.NET Development ideas and things
posts - 36, comments - 71, trackbacks - 0

My Links

News



I LOVE DataObject.NET
http://xceed.com
http://www.sharpcrafters.com/
http://www.telerik.com

Get this blog as a slideshow!
Powered by feedmap.net

Twitter












Tag Cloud

Archives

Post Categories

Catching unhandled exceptions and sending them to BugTracker.NET

clip_image002

1. Introduction

Have you ever been in a situation where the users are unable to explain how an error was displayed on their computer and moreover describe the details of the error message? Well… I wonder why I asked when I already knew the answer you’ll say.

A few weeks ago, the some users started testing the system; I realized our method of tracking bugs was not nearly good. We had an excel spreadsheet which had bug details and how we can reproduce the bug. We had problems with that each tester was now using their own version of a bug tracking spreadsheet, since excel does not allow shared access, so I downloaded the opensource Bugtracker.NET from codeplex to see if it could be of help, since we do not have  the Team Foundation Server.

2. Trapping unhandled exceptions

The first thing to do is to catch all unhandled exceptions, and to do that you added an event handler in the Application.

Program.cs

static class Program
{

static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
....
....
Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
....
....
}


static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Bug bug = Bug.Create();
string screenshotFile = bug.CaptureScreenShot();

bool sendScreenShot = false;
bool bugSent = false;
TaskDialog exceptionDialog = new TaskDialog();
exceptionDialog.MainIcon = TaskDialogIcon.Error;
exceptionDialog.MainInstruction = e.Exception.Message;
exceptionDialog.UseCommandLinks = false;
exceptionDialog.WindowTitle = "Error Occured!";
exceptionDialog.Content = string.Format("Unhandled Exception: {0}\nSource: {1}\nObject: {2}", e.Exception.Message, e.Exception.Source, e.Exception.TargetSite.ToString());
exceptionDialog.ExpandedByDefault = false;
exceptionDialog.ExpandedInformation = e.Exception.StackTrace;

exceptionDialog.VerificationText = "Do you want to send screenshot?";
exceptionDialog.VerificationFlagChecked = true;
exceptionDialog.FooterIcon = TaskDialogIcon.Information;

TaskDialogButton sendButton = new TaskDialogButton();
sendButton.ButtonId = 101;
sendButton.ButtonText = "Send";

TaskDialogButton cancelButton = new TaskDialogButton();
cancelButton.ButtonId = 102;
cancelButton.ButtonText = "Don't Send";

exceptionDialog.Buttons = new TaskDialogButton[] { sendButton, cancelButton };
int result = exceptionDialog.Show(null, out sendScreenShot);

if (result == sendButton.ButtonId)
{
bug.BugUrl = "http://server:88/insert_bug.aspx";
bug.MailText = string.Format("Unhandled Exception: {0}\nSource: {1}\nObject: {2}\nTrace: {3}",
e.Exception.Message, e.Exception.Source, e.Exception.TargetSite.ToString(), e.Exception.StackTrace);
bug.ProjectId = "ICEA.NET";
bug.UserName = "tester";
bug.Password = "tester";
bug.Subject = "User: [" + WindowsIdentity.GetCurrent().Name + "] "+ e.Exception.Message;

if (sendScreenShot)
bugSent = bug.WithAttachment(screenshotFile)
.ComposeMail()
.SendBugReport();
else
bugSent = bug.ComposeMail()
.SendBugReport();

if (bugSent)
MessageBox.Show("Details of error have sent to development team! Thanks.", "Message Sent", MessageBoxButtons.OK, MessageBoxIcon.Information);
else
MessageBox.Show("Could not send error details to development team!", "Message Failure", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}


}

The above code snippet will ensure that if an exception is unhandled then the method Application_ThreadException will be executed and the exception details are passed as an argument.

3. Capturing the screenshot

This is a very important part, because the screenshot will be attached to the email which is then sent to the server, so we can know what the user was doing when the exception occurred. The image is then converted to base64 format. This is simply changing the image to text so we can send it over HTTP.


public string ImageToBase64(Image image, System.Drawing.Imaging.ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();

// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}

private string CaptureImage(Point SourcePoint, Point DestinationPoint, Rectangle SelectionRectangle)
{
using (Bitmap bitmap = new Bitmap(SelectionRectangle.Width, SelectionRectangle.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(SourcePoint, DestinationPoint, SelectionRectangle.Size);
}
//return the string which represent the image
return ImageToBase64(bitmap, ImageFormat.Jpeg);
}
}

public string CaptureScreenShot()
{
Rectangle bounds = Screen.GetBounds(Screen.GetBounds(Point.Empty));
return CaptureImage(Point.Empty, Point.Empty, bounds);
}

4. Composing the Bug Mail

public Bug ComposeMail()
{
mail = "&username=" + HttpUtility.UrlEncode(_UserName) +
"&password=" + HttpUtility.UrlEncode(_Password) +
"&from=" + HttpUtility.UrlEncode(_UserName) +
"&short_desc=" + HttpUtility.UrlEncode(_Subject) +
"&projectid=" + HttpUtility.UrlEncode(_ProjectId);

if (_Attachment != string.Empty)
mail += "&message=" + HttpUtility.UrlEncode(_Attachment);
else
mail += "&message=" + HttpUtility.UrlEncode(_MailText);

return this;
}

5. Making the Web Request (HTTP)

Thanks to fiddler, I was able to analyse the details of the contents that are posted to the Bugtracker.NET. The tool downloadable with BugTracker.NET called bt2312 is written in C++. I translated part of it to C# and luckily .NET has very interesting libraries which allow you to perform most of the things out of the box.

clip_image006

Fiddler enables you to inspect your web requests and that was helpful, because after i inspected the web requests from bt2312 i was able to replicate the behaviour.

clip_image008

The labels above indicate the steps that have been made during the web request.

1. The application sends the data using HTTP.

2. The data sent (as text).

3. The response.

public bool SendBugReport()
{
bool Success = false;
ASCIIEncoding encoding = new ASCIIEncoding();


byte[] buffer = encoding.GetBytes(mail);

// Prepare web request...
HttpWebRequest myRequest =
(HttpWebRequest)WebRequest.Create(_BugUrl);

// We use POST ( we can also use GET )

myRequest.Method = "POST";

// Set the content type to a FORM
myRequest.ContentType = "application/x-www-form-urlencoded";
myRequest.UserAgent = Application.ProductName;
// Get length of content
myRequest.ContentLength = buffer.Length;

// Get request stream
Stream newStream = myRequest.GetRequestStream();

// Send the data.
newStream.Write(buffer, 0, buffer.Length);

// Close stream
newStream.Close();


// Assign the response object of 'HttpWebRequest' to a 'HttpWebResponse' variable.
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myRequest.GetResponse();

// Display the contents of the page to the console.
Stream streamResponse = myHttpWebResponse.GetResponseStream();

// Get stream object
StreamReader streamRead = new StreamReader(streamResponse);
Char[] readBuffer = new Char[256];

// Read from buffer
int count = streamRead.Read(readBuffer, 0, 256);

while (count > 0)
{
// get string
String resultData = new String(readBuffer, 0, count);
// Write the data
Success = resultData.Contains("OK:");
Console.WriteLine(resultData);
// Read from buffer
count = streamRead.Read(readBuffer, 0, 256);

}
// Release the response object resources.
streamRead.Close();
streamResponse.Close();

// Close response
myHttpWebResponse.Close();

return Success;
}


I have attached the Bug.cs class which contains all the code for creating a Bug report and sending it to and BugTracker.NET server. Apologies, i have not put a lot of comments in my code, if i revise this post i will probably do something about it.

Download Bug.cs

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

Print | posted on Tuesday, May 26, 2009 12:43 PM |

Feedback

Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

Hi.
This post is very useful!
The file: Bug.cs is missing. Can you upload it again?

Thanks.
8/24/2009 11:30 AM | Glauco
Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

I have sent you the file by mail. I am looking into re-uploading the file onto the blog.

Thanks
8/24/2009 6:12 PM | Malisa Ncube
Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

I'm also looking for the file, could you send me the file by mail, too?
1/15/2010 3:24 AM | Jean
Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

Could you send me the Bug.cs by mail, too?
10/18/2010 1:43 AM | Rafal
Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

Could you send me the Bug.cs by mail, too?
11/30/2010 4:52 AM | Alexandre Carvalho
Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

Very cool.

Two things: First, could you please send me the bug.cs file? Second, was this developed for a website or a desktop application?
12/28/2010 3:38 AM | Michael Bielski
Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

I'd like to have the file too, the download link is no longer working. Thanks!
6/4/2011 12:23 AM | michaels coupons
Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

Please send me the Bug.cs file or upload again.
11/1/2011 12:44 AM | Vasanth
Gravatar

# re: Catching unhandled exceptions and sending them to BugTracker.NET

Hi!
Fantastic idea !
Could you please send me the source file ?
Many thanks
11/11/2011 3:13 AM | NinjaCross
Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification:
 
 

Powered by: