Nannette Thacker ShiningStar.net

ASP.net Web Application Development

Sponsors

News

See all Blog Posts by Nannette.

Nannette Thacker, consultant and owner of Shining Star Services LLC, specializes in development of custom dynamic database driven web applications utilizing ASP.net technologies. Nannette has been developing ASP sites since 1997. Nannette has written numerous articles on web development techniques and tutorials.

Nannette is the owner and developer of ChristianSinglesDating.com.

 Subscribe in a reader





View Nannette  Thacker's profile on LinkedIn

September 2010 - Posts

ASP.NET Security Vulnerability Error Handling Project Part 3 - Sending Mail MailMessage()

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

Shining Star Services LLC on LinkedIn

ASP.NET Security Vulnerability Error Handling Project Part 2

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 Try

Return 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! 

Shining Star Services LLC on LinkedIn

ASP.NET Security Vulnerability Error Handling Project Part 1

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.Threading

Partial 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 delay

Dim 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

Shining Star Services LLC on LinkedIn

 

Concatenating the IN Clause using Oracle with Composite Keys

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

Shining Star Services LLC on LinkedIn

Installing Oracle Data Access Components (ODAC) ODP.NET

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

Shining Star Services LLC on LinkedIn

Advice to a student: What toys to buy...

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

 

Free development tools for students

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

Shining Star Services LLC on LinkedIn

 

More Posts