KnowDotNet

Log Browser Info For Trouble Shooting Web Application Errors

Get HTTPContext.Current Request Object in Exception Logger

by Les Smith

In logging exceptions thrown by a Web Site, you may need to record information regarding the Web Browser that is being used.  Sometimes the application may have a bug, sometimes the user does something you were not expecting, and sometimes the Web Browser that the user is using does not support some functionality that you have in your site.  Therefore you should record information regarding the current browser being used.  

You can create an ExceptionLogging DLL that can be used both by ASP.NET applications and Windows applications and the same method can be used.  In the method shown below, I test for the existence of an HTTPContext.Current object.  If it is not null I can access it to get browser information about the browser that the current user is using.  If the caller of the method is a Windows application, then the HTTPContext object will not be available and the method will not attempt to access Web Browser information.  Obviously, the SQL Parameters pertaining to the Web Browser properties must be optional parameters in the Stored Procedure that is being called to insert a record into the exception logging table in database.  The C# code below is the complete logging method including the namespaces required for logging to the database.  The stored procedure is database specific and is therefore not shown.


using System.Web;
using System;
using System.Data;
using System.Data.SqlClient;
public static string LogException(Exception ex,
                                  
string computerName,
                                  
int userId,
                                  
int applicationId,
                                  
string connectionString)
{
    
string returnValue = "-1";
    
SqlConnection sqlConn = null;
    
StringBuilder sbAdditionalData = new StringBuilder();

    
// Get any additional data that was passed in with the exception
   try
   {
        sqlConn =
new SqlConnection(connectionString);

        
SqlCommand sqlCommand = new SqlCommand("usp_SPA_InsertException", sqlConn);
        sqlCommand.CommandType =
CommandType.StoredProcedure;

        sqlCommand.Parameters.Add(
new SqlParameter("@ExceptionDateTime",
            
SqlDbType.DateTime));
        sqlCommand.Parameters.Add(
new SqlParameter("@ComputerName",
            
SqlDbType.VarChar, 255));
        sqlCommand.Parameters.Add(
new SqlParameter("@UserId", SqlDbType.Int, 4));
        sqlCommand.Parameters.Add(
new SqlParameter("@ExceptionMessage",
            
SqlDbType.Text));
        sqlCommand.Parameters.Add(
new SqlParameter("@ExceptionSource",
            
SqlDbType.Text));
        sqlCommand.Parameters.Add(
new SqlParameter("@ExceptionStackTrace",
            
SqlDbType.Text));
        sqlCommand.Parameters.Add(
new SqlParameter("@AdditionalData",
            
SqlDbType.Text));
        sqlCommand.Parameters.Add(
new SqlParameter("@ApplicationId",
            
SqlDbType.Int, 4));

        #region if HTTPContext is available add browser parameters
        
// try to get the current HTTP Context
        if (HttpContext.Current != null)
        {
            sqlCommand.Parameters.Add(
new SqlParameter("@UserHostAddress",
                
SqlDbType.VarChar, 255));
            sqlCommand.Parameters.Add(
new SqlParameter("@BrowserType",
                
SqlDbType.VarChar, 255));
            sqlCommand.Parameters.Add(
new SqlParameter("@BrowserName",
                
SqlDbType.VarChar, 255));
            sqlCommand.Parameters.Add(
new SqlParameter("@BrowserVersion",
                
SqlDbType.VarChar, 255));
            sqlCommand.Parameters.Add(
new SqlParameter("@BrowserMajorVersion",
                
SqlDbType.VarChar, 255));
            sqlCommand.Parameters.Add(
new SqlParameter("@BrowserMinorVersion",
                
SqlDbType.VarChar, 255));
            sqlCommand.Parameters.Add(
new SqlParameter("@Platform",
                
SqlDbType.VarChar, 255));
            sqlCommand.Parameters.Add(
new SqlParameter("@IsBeta", SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@IsCrawler", SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@IsAOL", SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@IsWin16", SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@IsWin32", SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@SupportsFrames",
                
SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@SupportsTables",
                
SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@SupportsCookies",
                
SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@SupportsVBScript",
                
SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@SupportsJavaScript",
                
SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@SupportsJavaApplets",
                
SqlDbType.Bit));
            sqlCommand.Parameters.Add(
new SqlParameter("@SupportsActiveXControls",
                
SqlDbType.Bit));
        }
// if
        #endregion

        sqlCommand.Parameters.Add(new SqlParameter("@ReturnValue",
            
SqlDbType.Int, 4));
        sqlCommand.Parameters[0].Value =
DateTime.Now;
        sqlCommand.Parameters[1].Value = computerName;
        sqlCommand.Parameters[2].Value = userId;
        sqlCommand.Parameters[3].Value = ex.Message;
        
if (string.IsNullOrEmpty(ex.Source))
        {
            sqlCommand.Parameters[4].Value =
DBNull.Value;
        }
        
else
        {
            sqlCommand.Parameters[4].Value = ex.Source;
        }

        
if (string.IsNullOrEmpty(ex.StackTrace))
        {
            sqlCommand.Parameters[5].Value =
DBNull.Value;
        }
        
else
        {
            sqlCommand.Parameters[5].Value = ex.StackTrace;
        }

        sqlCommand.Parameters[6].Value = sbAdditionalData.ToString();
        sqlCommand.Parameters[7].Value = applicationId;

        #region
if browser parameters were created set values
        
if (HttpContext.Current != null)
        {
            
if (string.IsNullOrEmpty(HttpContext.Current.Request.UserHostAddress))
            {
                sqlCommand.Parameters[8].Value =
DBNull.Value;
            }
// if
            else
            {
                sqlCommand.Parameters[8].Value =
                  
HttpContext.Current.Request.UserHostAddress;
            }
// else
            if (string.IsNullOrEmpty(HttpContext.Current.Request.Browser.Type))
            {
                sqlCommand.Parameters[9].Value =
DBNull.Value;
            }
// if
            else
            {
                sqlCommand.Parameters[9].Value =
                    
HttpContext.Current.Request.Browser.Type;
            }
// else

            if (string.IsNullOrEmpty(HttpContext.Current.Request.Browser.Browser))
            {
                sqlCommand.Parameters[10].Value =
DBNull.Value;
            }
// if
            else
            {
                sqlCommand.Parameters[10].Value =
                    
HttpContext.Current.Request.Browser.Browser;
            }
// else

            if (string.IsNullOrEmpty(HttpContext.Current.Request.Browser.Version))
            {
                sqlCommand.Parameters[11].Value =
DBNull.Value;
            }
// if
            else
            {
                sqlCommand.Parameters[11].Value =
                    
HttpContext.Current.Request.Browser.Version;
            }
// else

            if (HttpContext.Current.Request.Browser.MajorVersion != null)
            {
                sqlCommand.Parameters[12].Value =
DBNull.Value;
            }
// if
            else
            {
                sqlCommand.Parameters[12].Value =
                    
HttpContext.Current.Request.Browser.MajorVersion;
            }
// else

            
if (HttpContext.Current.Request.Browser.MinorVersion != null)
            {
                sqlCommand.Parameters[13].Value =
DBNull.Value;
            }
// if
            else
            {
                sqlCommand.Parameters[13].Value =
                    
HttpContext.Current.Request.Browser.MinorVersion.ToString();
            }
// else

            
if (string.IsNullOrEmpty(HttpContext.Current.Request.Browser.Platform))
            {
                sqlCommand.Parameters[14].Value =
DBNull.Value;
            }
// if
            else
            {
                sqlCommand.Parameters[14].Value =
                    
HttpContext.Current.Request.Browser.Platform;
            }
// else

            sqlCommand.Parameters[15].Value =
                
HttpContext.Current.Request.Browser.Beta;
            sqlCommand.Parameters[16].Value =
                
HttpContext.Current.Request.Browser.Crawler;
            sqlCommand.Parameters[17].Value =
                
HttpContext.Current.Request.Browser.AOL;
            sqlCommand.Parameters[18].Value =
                
HttpContext.Current.Request.Browser.Win16;
            sqlCommand.Parameters[19].Value =
                
HttpContext.Current.Request.Browser.Win32;
            sqlCommand.Parameters[20].Value =
                
HttpContext.Current.Request.Browser.Frames;
            sqlCommand.Parameters[21].Value =
                
HttpContext.Current.Request.Browser.Tables;
            sqlCommand.Parameters[22].Value =
                
HttpContext.Current.Request.Browser.Cookies;
            sqlCommand.Parameters[23].Value =
                
HttpContext.Current.Request.Browser.VBScript;
            sqlCommand.Parameters[24].Value =
                
HttpContext.Current.Request.Browser.JavaScript;
            sqlCommand.Parameters[25].Value =
                
HttpContext.Current.Request.Browser.JavaApplets;
            sqlCommand.Parameters[26].Value =
                
HttpContext.Current.Request.Browser.ActiveXControls;
            sqlCommand.Parameters[27].Direction =
                
ParameterDirection.ReturnValue;
        }
        #endregion // set browser variables
        else
        {
           sqlCommand.Parameters[8].Direction =
ParameterDirection.ReturnValue;
        }
// else

        sqlConn.Open();
        sqlCommand.ExecuteNonQuery();

        returnValue = sqlCommand.Parameters[
"@ReturnValue"].Value.ToString();
    }
    
catch (Exception saveEx)
    {
        
// Write the original exception and what ever exception
        // above to the eventlog since saving to the database failed.
        StringBuilder sbMessage = new StringBuilder();
        sbMessage.Append(
"LogException Exception Message: ");
        sbMessage.Append(saveEx.Message);
        sbMessage.Append(
Environment.NewLine);
        sbMessage.Append(
"LogException Exception StackTrace: ");
        sbMessage.Append(saveEx.StackTrace);
        sbMessage.Append(
Environment.NewLine);
        sbMessage.Append(
"Original Exception Message: ");
        sbMessage.Append(ex.Message);
        sbMessage.Append(
Environment.NewLine);
        sbMessage.Append(
"Original Exception StackTrace: ");
        sbMessage.Append(ex.StackTrace);
        sbMessage.Append(
Environment.NewLine);
        sbMessage.Append(
"Original Exception Additional Data: ");
        sbMessage.Append(sbAdditionalData.ToString());
        sbMessage.Append(
Environment.NewLine);
        sbMessage.Append(
"AppId: ");
        sbMessage.Append(applicationId.ToString());

        
try
        {
            
EventLog.WriteEntry("SPA", sbMessage.ToString(),
              
EventLogEntryType.Error, 1000);
        }
        
catch
        {
            
// Unable to write to the eventlog
        }

        returnValue =
"EL-1000";
    }
    
finally
    {
        
if (sqlConn != null)
        {
           sqlConn.Close();
           sqlConn.Dispose();
        }
    }

    
return returnValue;
}

You might notice another trick that refactoring buffs might not agree with, but I am using #regions within a method.  This is a poor man's refactoring methodology.  Also, as of VS2008, it can only be done in C#, not VB.NET.  However, in a long method like the one above, that is only doing one thing (calling a stored procedure) it actually makes sense.  Although you do not reduce the physical size of the method, it does increase the readability of the code and in fact may make it easier to follow and thus maintain than using an ExtractMethod refactoring just to reduce the size of the method.

Need to automatically organize your code windows?  You'll be amazed how easy it is to keep the code in your code windows organized.  TRY IT FREE FOR 30 DAYS BY CLICKING HERE.



Automatically generate braces in C#! Try CSharpCompleter and stop wasting valuable time needlessly typing hundreds of braces {} daily.  Try CSharpCompleter for 30 DAYS FREE.



Ask a Question, or give your feedback on my articles or products by going to the KnowDotNet Forum or by clicking on My Blog.
  

You can also email me directly at les@KnowDotNet.com.