September 2010 - Posts
Added note: A patch has been created. See Scott Guthrie's post here.
In ASP.NET Security Vulnerability Error Handling Project Part 1, we discussed implementing a project that utilizes the suggestions made in Scott Guthrie's post on ASP.NET Security Vulnerability. Even after Microsoft releases a patch for this security vulnerability, this working project will still be valuable for generating your error messages and sending emails.
I showed how to setup the web.config file, add the sleep delay, and optionally display the error to the screen for developer debugging. Now we'll discuss the actual error handling.
In ASP.NET Security Vulnerability Error Handling Project Part 2, I showed how to retrieve the Exception.
In this post, Part 3, we will review the SendMailMessage function. In order to have good error handling on your site, you should have some method of sending the error messages received by the users to the developer. We will send them via email. Of course, if the error message pertains to the mail server being down or there is an error in your master page, you're out of luck. :) But otherwise, this will work fine.
The complete project can be found in this NannetteThackerErrorHandling.zip file.
My SendMailMessage function is a combination of the best tips I've seen on the web for sending mail. I've added a few of my own snippets, such as looping through comma delimited email addressses to allow sending to multiple recipients. Also, if an empty string is returned, no error was generated.
Public Shared Function SendMailMessage(ByVal toEmail As String, _
ByVal subject As String, ByVal body As String, _
Optional ByVal fromEmail As String = "", _
Optional ByVal bcc As String = "", _
Optional ByVal cc As String = "", _
Optional ByVal attachmentFileName As String = "" _
) As String
Try' Instantiate a new instance of MailMessage
Dim mMailMessage As New MailMessage()
' Set the sender address of the mail message
If fromEmail <> String.Empty Then
mMailMessage.From = New MailAddress(fromEmail)
Else
mMailMessage.From = New MailAddress(WebConfigurationManager.AppSettings("MailFrom"), "My Website Name")
End If
If attachmentFileName <> String.Empty Then
Dim attachmentfile As New System.Net.Mail.Attachment(attachmentFileName)
mMailMessage.Attachments.Add(attachmentfile)
End If
If toEmail = String.Empty Then
toEmail = WebConfigurationManager.AppSettings("ErrorHandlingMailTo")
End If
toEmail = Trim(toEmail)
' trim off any spaces on the right
If Right(toEmail, 1) = "," Then
toEmail = Left(toEmail, Len(toEmail) - 1)
End If
Dim mailTo As String = toEmail
' allow pass in a set of comma delimited names and add the address per recipient
If Not mailTo Is Nothing And mailTo <> String.Empty Then
Dim newaddy As String() = Split(mailTo, ",")
For Each addr In newaddy
If Len(addr) <> 0 Then
If Not mMailMessage.To.Contains(New MailAddress(addr)) Then
mMailMessage.To.Add(addr)
End If
End If
Next
End If
' Check if the bcc value is null or an empty string
If Not bcc Is Nothing And bcc <> String.Empty Then
'Set the Bcc address of the mail message
Dim newaddy As String() = Split(bcc, ",")
For Each addr In newaddy
If Len(addr) <> 0 Then
If Not mMailMessage.To.Contains(New MailAddress(addr)) Then
mMailMessage.Bcc.Add(New MailAddress(addr))
End If
End If
Next
End If' Check if the cc value is null or an empty value
If Not cc Is Nothing And cc <> String.Empty Then
' Set the CC address of the mail message
Dim newaddy As String() = Split(cc, ",")
For Each addr In newaddy
If Len(addr) <> 0 Then
If Not mMailMessage.To.Contains(New MailAddress(addr)) Then
mMailMessage.Bcc.Add(New MailAddress(cc))
End If
End If
Next
End If
' Set the subject of the mail message
mMailMessage.Subject = subject' Set the body of the mail message
body = "<font face=""verdana"">" & body & "</body>"
mMailMessage.Body = body
' Secify the format of the body as HTML
mMailMessage.IsBodyHtml = True' Set the priority of the mail message to normal
mMailMessage.Priority = MailPriority.Normal ' Instantiate a new instance of SmtpClient
Dim mSmtpClient As New SmtpClient()
mSmtpClient.Host = WebConfigurationManager.AppSettings("MailHost")
If Not GetValues.IsLocalHost() Then ' don't send if testing locally
' Send the mail message
mSmtpClient.Send(mMailMessage)
End If
' dispose and set to nothing
If attachmentFileName <> String.Empty Then
attachmentFileName = Nothing
mMailMessage.Attachments.Dispose()
End If
mSmtpClient =
Nothing
Return String.Empty ' success
Catch ex As Exception
Return ex.Message
End Try
End Function
The complete project can be found in this NannetteThackerErrorHandling.zip file.
May your dreams be in ASP.NET!
Nannette Thacker

Added note: A patch has been created. See Scott Guthrie's post here.
In ASP.NET Security Vulnerability Error Handling Project Part 1, we discussed implementing a project that utilizes the suggestions made in Scott Guthrie's post on ASP.NET Security Vulnerability. Even after Microsoft releases a patch for this security vulnerability, this working project will still be valuable for generating your error messages and sending emails.
I showed how to setup the web.config file, add the sleep delay, and optionally display the error to the screen for developer debugging. Now we'll discuss the actual error handling.
The complete project can be found in this NannetteThackerErrorHandling.zip file.
In the ErrorHandling class, we retrieve the last error as a System.Exception. We use the function "getDebugValues()" to retrieve more detailed debugging information. We also get the HTML error message. All are sent via email to the email address as setup in the web.config file:
Public Shared Function Application_Error(ByVal getLastError As System.Exception, _
ByVal rawUrl As String, ByVal userName As String) As String
Dim getString As String = String.Empty
Try
' Get the error details
Dim lastErrorWrapper As HttpException = TryCast(getLastError, HttpException)
Dim lastError As Exception = lastErrorWrapper
Dim lastErrorTypeName As String = lastError.GetType().ToString()
Dim lastErrorMessage As String = lastError.Message
Dim lastErrorStackTrace As String = lastError.StackTrace
Dim ToAddress As String = WebConfigurationManager.AppSettings("ErrorHandlingMailTo")
Dim Subject As String = "An Error Has Occurred!"
getString = getString & "<table cellpadding=""5"" cellspacing=""0"" border=""1"">" & Environment.NewLine
getString = getString & GetValues.FormatTableRow("TIME:", Date.Now().ToString)
getString = getString & GetValues.FormatTableRow("URL:", rawUrl)
getString = getString & GetValues.FormatTableRow("USER:", userName)
getString = getString & GetValues.FormatTableRow("EXCEPTION TYPE:", lastErrorTypeName)
getString = getString & GetValues.FormatTableRow("MESSAGE:", lastErrorMessage)
getString = getString & GetValues.FormatTableRow("STACK TRACE:", lastErrorStackTrace.Replace(Environment.NewLine, "<br />"))
getString = getString & " </table>"
Dim body As String = String.Empty
body = String.Format(Environment.NewLine & "<html>" & Environment.NewLine & _
" <body>" & Environment.NewLine & " <h1>An Error Has Occurred!</h1>" & Environment.NewLine)
getString = getString & GetValues.getDebugValues() ' add more details to aid in debugging
' display Yellow Screen of Death for this error
Dim YSODmarkup As String = lastErrorWrapper.GetHtmlErrorMessage()
If Not String.IsNullOrEmpty(YSODmarkup) Then
getString = getString & YSODmarkup
End If
body = body & getString &
" </body>" & Environment.NewLine & "</html>"'For more information on sending email from an ASP.NET application see:
'http://aspnet.4guysfromrolla.com/articles/072606-1.aspx
MailHelper.SendMailMessage(ToAddress, Subject, body) Catch ex As Exception
End TryReturn getString ' return the getString value to optionally print to screen on debugging...
End Function
The getValues class functions are included in the final ZIP project. In ASP.NET Security Vulnerability Error Handling Project Part 3 I'll show the SendMailMessage function.
The complete project can be found in this NannetteThackerErrorHandling.zip file.
May your dreams be in ASP.NET!

Added note: A patch has been created. See Scott Guthrie's post here.
After having read Scott Guthrie's post on ASP.NET Security Vulnerability, I decided to take my existing error handling code, update it with his suggested sleep delay, and put it into a separate VB.NET Visual Studio project to share with others.
In my project, you may optionally display the details of the error on the page if you update the code to set the debug flag to true, for instance, if the developer is logged in. I also send the error message and site specific details to the developer via email. That way, you will receive all error details, even though the user does not. Even after Microsoft releases a patch for this security vulnerability, this working project will still be valuable for generating your error messages and sending emails.
The complete project can be found in this NannetteThackerErrorHandling.zip file.
Through the years, I have borrowed from other's examples on the web. Thanks to Scott Mitchell for his HttpException handling retrieval. See more details of Gracefully Responding to Unhandled Exceptions - Displaying User-Friendly Error Pages and Gracefully Responding to Unhandled Exceptions - Processing Unhandled Exceptions and Displaying a Custom Error Page.
Web.Config
To use the code from this project, update the web.config settings to add your own values:
<appSettings>
<add key="ErrorHandlingMailTo" value="yourmail@yourmail.com"/>
<add key="MailFrom" value="yourmail@yourmail.com"/>
<add key="MailHost" value="smtp.yourmail.com"/>
</appSettings>
Turn on customErrors:
<
customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Module/Admin/ErrorPages/Error.aspx">
</customErrors>
And make sure you turn off the debugging prior to publishing:
<compilation debug="true" strict="false" explicit="true">
MasterPage and Default
I created a simple MasterPage because I like my error screen to use the site's MasterPage. The Default page simply has two buttons for testing purposes. One generates a Coding Error and the other generates a page not found error.

When running locally in debug mode, selecting the "Generate Coding Error" button will display an "InvalidCastException" error. Hit "F5" to continue. The error page will display without providing details of the error.

Click your BACK button and try the "Generate Page Not Found Error" button. Both display the same page and error.
To generate these errors, I simply create them on the button clicks:
Protected Sub btnCodingError_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCodingError.Click
Dim this As String = "that"
Dim id As Integer = this
End Sub
Protected Sub btnPageNotFound_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPageNotFound.Click
Response.Redirect("FakePage.html", False)
End Sub
Error Page
On my Error.aspx page, I simply display a non-descript error message. I place a label for an optional errorMessage for the developer.
<img src="<%=ResolveUrl("~/Module/Images/oops.jpg") %>" alt="Oops!" align="left" hspace="15" vspace="15" />
<br /><h2>Oops! Did I do that?</h2>
An unexpected error has occurred. The administrator has been notified.<br />
<br />
<asp:Label ID="errorMessage" runat="server" Text=""></asp:Label>
In my code-behind:
Option
Strict On
Option Explicit On
Imports System.Security.Cryptography
Imports System.ThreadingPartial Class Modules_ErrorPages_Error
Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
' http://weblogs.asp.net/scottgu/archive/2010/09/18/important-asp-net-security-vulnerability.aspx
' add sleep delayDim delay As Byte() = New Byte(0) {}
Dim prng As RandomNumberGenerator = New RNGCryptoServiceProvider()
prng.GetBytes(delay)
Thread.Sleep(CType(delay(0), Integer))
Dim disposable As IDisposable = TryCast(prng, IDisposable)
If Not disposable Is Nothing Then
disposable.Dispose()
End If
' email yourself error details...
' optionally add code to check if web administrator/developer is logged in, if so display on screen in errorMessage
' if not, just send the email...
' change debug to false prior to publishing...
Dim debug As Boolean = False
If debug Then
errorMessage.Text = ErrorHandling.Application_Error(Server.GetLastError(), Request.RawUrl, User.Identity.Name)
Else
ErrorHandling.Application_Error(Server.GetLastError(), Request.RawUrl, User.Identity.Name)
End If
Catch ex As Exception
End Try
End Sub
End Class
Notice if you turn on the debug flag, the error will be displayed to the screen:

In ASP.NET Security Vulnerability Error Handling Project Part 2 of this post, I'll show the actual ErrorHandling class. In ASP.NET Security Vulnerability Error Handling Project Part 3 I'll show the SendMailMessage function.
The complete project can be found in this NannetteThackerErrorHandling.zip file.
May your dreams be in ASP.NET!
Nannette Thacker

Most .NET developers are familiar with how to concatenate fields in SQL Server 2008:
select firstName + ' ' + lastName as UserName from Reviewers
In your ASP.NET development, you may be required to work with various database types. I’m going to show how to use the CONCAT function in Oracle, specifically within the IN clause. In your SQL query WHERE clause, first you must use the CONCAT function to combine the desired fields, then in your SELECT clause again CONCAT the selected fields which must match from the first table. This is typically used with a composite key from the first table which must be found to match data in the second table.
And, because this isn’t an Oracle blog, I will also include how to open and close connections and run queries within .NET using Oracle’s Data Access Components. At the top of your class, be sure to import the Oracle.DataAccess.Client:
VB.NET
Imports Oracle.DataAccess.Client
Build your query:
Dim sql As String = String.Empty
sql = "SELECT * FROM TBL_OPERATION " & _
" WHERE CONCAT(op_symbol,CONCAT(' - ', op_code))" & _
" IN (SELECT CONCAT(op_symbol,CONCAT(' - ', op_code))" & _
" FROM TBL_REVIEW_OPERATION " & _
" WHERE op_symbol = :op_symbol AND prod_number = :prod_number"
Dim cmd As New OracleCommand()
Using con As New OracleConnection(GetConnectionString)
con.Open()
cmd = New OracleCommand(sql, con)
cmd.CommandType = CommandType.Text
cmd.Parameters.Add("op_symbol", OracleDbType.Varchar2,5).Value = _
op_symbol
cmd.Parameters.Add("prod_number ", OracleDbType.Varchar2,3).Value = _
prod_number
cmd.ExecuteNonQuery()
End Using
' using blocks automatically call Dispose() and close the connection
In the above example, we separate each field with a hyphen, so the result of two columns might look like this:"233-421"
Instead of this:
"233421"
It is important to have some form of divider so that you don’t pull unintended data. Such as if the first field were 23 and the second 3421, or 2334 and 21. By using dividers, you’re always sure to get 233 and 421 as the two concatenated field values.
Other common Oracle parameter types include:
cmd.Parameters.Add("RecordUpdatedUserId", OracleDbType.Decimal).Value = RecordUpdatedUserId
cmd.Parameters.Add("RecodUpdatedDate", OracleDbType.Date).Value = Now()
cmd.Parameters.Add("ActionDescription", OracleDbType.Clob, 3000).Value = ActionDescription
For further information on SQL Concatenation, visit this article.
May your dreams be in ASP.NET!
Nannette Thacker

In the past, Microsoft has provided their own Oracle classes with: System.Data.OracleClient
But with .NET framework 4.0, Microsoft will apparently be deprecating the use of System.Data.OracleClient. See this article on Microsoft Kills Its Oracle Data Provider for ADO.NET.
I've been using the Oracle Data Access Components (ODAC) for several years and will provide some information on downloading and installing Oracle's Data Provider.
First, download the ODAC at Oracle's Oracle Data Access Components Download page. (Optionally, visit Oracle's .NET page for the latest news on support for .NET.)
Find your appropriate ODAC download on the Oracle Data Access Components page.
Select the executable to install it, for instance:
ODAC1020221.exe
Then go to the install directory and run setup.exe
Within your Visual Studio project, right click your web site within Solution Explorer and select to Add Reference. Find the installed component within a directory similar to this:
C:\oracle\product\10.2.0\client_1\ODP.NET\bin\2.x
Make sure ODAC is also installed on the web server that is hosting the application.
May your dreams be in ASP.NET!
Nannette Thacker

A computer science student wrote me and asked me if I had $500 to spend on one application toy, what would I buy? He was asking if purchasing the Adobe Creative Suite would be a good tool for him. My reply:
It depends on what you want to do. Do you want to learn to do the graphic arts side of things? What shows on the page? Or do you want to do the programming, the code in the background that puts things on the page? The code that accesses the database and displays the data?
If you want to be a programmer, use the free visual studio express edition to start, then after you've learned it and are sure you want to be a programmer, purchase the latest visual studio version (currently 2010) so that you can work with projects. HOWEVER, if you are going to work for a company, don't buy it. Just use the free version while learning at home, and let your company buy your development environment for you.
Programmers RARELY do the art work too. CS5 is nice if you are artistic and expect to spend a lot of time working with design and art. If NOT, then don't use your limited funds to purchase something you likely won't use.
As a student, I'd save my money to pay bills. There are so many free tools out there you can use while learning. You can use trial versions as well. Once you get that job, your company will buy your toys.
May your dreams be in ASP.NET!
Nannette Thacker
My friend, Joseph Palmer, shared with me these links for free development tools for students. He writes:
Here is an unbelievable link where I was able to get VS 2010 Pro free as a student, it is even for high schoolers. Hope someone can use these-
Microsoft student page, everything is totally free with limits on use though:
https://www.dreamspark.com/default.aspx
Here is another link for Adobe Student Discounts:
http://www.adobe.com/education/students/
---
Another added note, we've always purchased our student editions from Academic Superstore. You might compare prices and see what you think. With 3 very computer literate daughters, it's nice to get a discount on their toys.
May your dreams be in ASP.NET!
Nannette

More Posts