Screen Grabbing with .NET
How to programmatically connect to a webpage and get content via .NET.


How to programmatically connect to a webpage and get content via .NET.


So you have an ArrayList of strings and you want to return it as a string[] array. It's really easy:
return (string[])arrayList.ToArray(typeof(string));
If you didn't know the using statement given in the title is valid, then congratulations! Now you do. ;-)
Why would you use this instead of the more general using Earth.LivingBeings.HomoSapiens.Female? Well:
Suppose you Autopsy.cs uses both Earth.LivingBeings.Humans.Female as well as the Earth.LivingBeings.Monkeys.Female classes. One way to resolve the naming conflict is to laborously type out the fully-qualified class name each time you use it. The other way is to:
using HumanFemale = Earth.LivingBeings.Humans.Female;
using MonkeyFemale = Earth.LivingBeings.Monkeys.Female;
protected void Page_Load(object sender, EventArgs e)
{
try
{
MailMessage message = new MailMessage(
"from@example.com",
"to@example.com",
"Some Important Message",
"This is a test message and it's not that important.");
SmtpClient client = new SmtpClient("your.smtp.server.com");
System.Net.NetworkCredential credentials = new
System.Net.NetworkCredential(
"username",
"password");
client.UseDefaultCredentials = true;
client.Credentials = credentials;
client.Send(message);
}
catch (Exception ex)
{
Response.Write("Whoops! Couldn't send the e-mail: " +
ex.ToString());
}
}
Storing binary data directly in the database is a fairly common practice. I recently found myself wondering how to read binary data from the database and write it to the browser.
For example, suppose you have a PDF file stored in the database. How do you send it to the browser? I ended up with this:
protected void Page_Load(object sender, EventArgs e)
{
using (SqlConnection connection = new SqlConnection("Connection string goes here"))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "dbo.GetPdf";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("@Id", 1);
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.Read() == false)
{
return;
}
int contentLength = Convert.ToInt32(reader.GetBytes(0, 0, null, 0, int.MaxValue));
byte[] buffer = new byte[contentLength];
reader.GetBytes(0, 0, buffer, 0, contentLength);
Response.ContentType = "application/pdf";
Response.BinaryWrite(buffer);
}
}
}
}
This works, but I wonder if it's the most efficient way to solve the problem? For example, we're calling the GetBytes method twice, which means that we're actually reading the whole document just to get its length. If the document is huge, this is wasteful. In that situation, I'm guessing having a fixed-sized buffer and reading the data in a while loop would be the way to go.
EXEC sys.sp_tables
But this will list every single table, including all the system tables, which we rarely ever want. To list only tables created by the user, add a @table_owner parameter. For most databases, this will be "dbo":
EXEC sys.sp_tables NULL, 'dbo', NULL, NULL, NULL
Before we get on with the article, a couple of quick announcements. Regular readers of this site know well my tendency to put this site through an obnoxious number of redesigns. Sometimes I feel like I'm in a never-ending design cycle, because I'm always tweaking something here or adding something there. Anyway, I once again found myself twitching to do a redesign. I hesitate to say that I got tired of the old ( well, current, as of this entry ) theme, because I still like it; however, it most definitely grew old. So: look for the new design soon — like over the weekend; definitely over next week. :-)
Moving on.
public void DownloadPdf(string path)
{
try
{
System.IO.StreamReader reader = System.IO.File.OpenText(path);
}
catch (System.UnauthorizedAccessException ex)
{
// Hey, you don't have access to the file!
}
catch (System.IO.FileNotFoundException ex)
{
// Hey, the file doesn't exist
}
catch (Exception ex)
{
// Something bad happened
}
}
protected override void OnError(EventArgs e)
{
Exception exception = HttpContext.Current.Server.GetLastError();
// Inform the user about the exception, log it, and do whatever
// else you want to do here.
}
// In global.asax
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = HttpContext.Current.Server.GetLastError();
// Do whatever with the exception here.
}
You might notice that catching exceptions at the application level is remarkably similar to catching them at the page level. This is good — one less thing for us to have to remember. :-)
What if you want to have your application continue on its merry way, not stop dead in its tracks because of the exception? For example, suppose the user is trying to upload a file and your application throws an exception because the file is too big. It would be nice if your application lets the user to continue working instead of taking him to the jarringly-ugly yellow page of death error page?
This is what happens when you catch an exception (aka, method 1), so you don't need to do anything special. However, it's a pain to have to wrap every single method in a try...catch block. The way to clear exceptions/errors with the other two methods is with the Server class' handy ClearError method:
// In global.asax
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = HttpContext.Current.Server.GetLastError();
// Do whatever with the exception here.
HttpContext.Current.Server.ClearError();
}
You should, at some point, trap all exceptions that occur in your application. At the very least, you should redirect the user to a custom error page. Not only are the default error pages produced by ASP .NET horrendously ugly, they're usually unhelpful to the end-user. Also, they reveal information about your code, which is bad from a security-viewpoint. ASP .NET provides 3 very easy ways to trap errors in an application.
My favorite method — well, my second favorite method — of catching exceptions is using the Global.asax's Application_Error method. ( My favorite way is to use HttpModules, which I'm going to talk about in a future article. )
exec sp_stored_procedures
That's it. That single line/word will list all the stored procedures in the currently-active database.
DatabaseName.dbo.sp_stored_procedures
This line lists all the stored procedures in the specified database.
Another useful stored procedure is sp_helptext, which shows you the actual (SQL) stored procedure:
DatabaseName.dbo.sp_helptext StoredProcedureName
Using these stored procedures with a linked server is straight-forward, too:
NameOfTheLinkedServer.NameOfTheDatabase.DatabaseOwner.sp_stored_procedures