/// <summary> /// Executes a raw sql statement. BEWARE OF SQL INJECTION ATTACKS. Use for hardcoded sql only. /// </summary> /// <param name="sql">The sql statement to run as a scalar</param> /// <returns>The scalar result</returns> public object ExecuteRawSqlScalar(string sql) { ArgumentValidationHelper.CheckArgumentNotNull(sql, "sql"); IDbConnection con = null; try { con = OpenConnection; var cmd = CreateCommand(con); cmd.CommandText = sql; return(cmd.ExecuteScalar()); } catch (Exception ex) { Log.Log ("Error reading database : " + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 10, true), LogCategory.Exception); Log.Log("Sql: " + sql, LogCategory.Exception); Console.WriteLine (@"Error reading database : " + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 10, true)); Console.WriteLine(@"Connect string: " + this.ErrorSafeConnectString()); throw new DatabaseReadException ("There was an error reading the database. Please contact your system administrator.", "The command ExecuteScalar could not be completed.", ex, sql, ErrorSafeConnectString()); } finally { if (con != null && con.State != ConnectionState.Closed) { con.Close(); } } }
///<summary> /// Returns the value of a property of an object using reflection ///</summary> ///<param name="obj">The object to get the value from</param> ///<param name="propertyName">The name of the property to get the value from</param> ///<returns>The value of the specified property of the supplied object</returns> ///<exception cref="HabaneroArgumentException">This error is thrown when an invalid parameter is given</exception> ///<exception cref="TargetInvocationException">This error is thrown when there is an error in finding the property on the supplied object</exception> ///<exception cref="Exception">This is a general exception that is thrown if there is an error in retrieving the value.</exception> public static object GetPropertyValue(object obj, string propertyName) { if (obj == null) { throw new HabaneroArgumentException("obj", "The argument should not be null"); } if (String.IsNullOrEmpty(propertyName)) { throw new HabaneroArgumentException("propertyName", "The argument should not be null"); } Type type = obj.GetType(); string className = type.Name; try { PropertyInfo propInfo = GetPropertyInfo(type, propertyName); if (propInfo == null) { throw new TargetInvocationException(new Exception( String.Format("Virtual property '{0}' does not exist for object of type '{1}'.", propertyName, className))); } object propValue = propInfo.GetValue(obj, new object[] { }); return(propValue); } catch (TargetInvocationException ex) { string message = String.Format("Error retrieving public property '{0}' from object of type '{1}'", propertyName, className); _log.Log(String.Format("{0}" + Environment.NewLine + "{1}", message, ExceptionUtilities.GetExceptionString(ex.InnerException, 8, true)), LogCategory.Exception); throw new HabaneroApplicationException(message, ex.InnerException); } }
/// <summary> /// Loads a data reader with the given raw sql select statement for the specified transaction /// </summary> /// <param name="selectSql">The sql statement as a string</param> /// <param name="transaction">Thransaction that gives the context within which the sql statement should be executed</param> /// <returns>Returns an IDataReader object with the results of the query</returns> /// <exception cref="DatabaseReadException">Thrown when an error /// occurred while setting up the data reader. Also sends error /// output to the log.</exception> public IDataReader LoadDataReader(string selectSql, IDbTransaction transaction) { if (selectSql == null) { throw new ArgumentNullException("selectSql"); } IDbConnection con = null; try { con = transaction.Connection; var cmd = CreateCommand(con); cmd.Transaction = transaction; cmd.CommandType = CommandType.Text; cmd.CommandText = selectSql; return(cmd.ExecuteReader()); } catch (Exception ex) { Log.Log ("Error reading from database : " + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 10, true), LogCategory.Exception); Log.Log("Sql: " + selectSql, LogCategory.Exception); throw new DatabaseReadException ("There was an error reading the database. Please contact your system administrator.", "The DataReader could not be filled with", ex, selectSql, ErrorSafeConnectString()); } }
///<summary> /// Sets the value of a property of an object using reflection ///</summary> ///<param name="obj">The object for which to set the value</param> ///<param name="propertyName">The name of the property to be set</param> ///<param name="value">The value that is to be set</param> ///<exception cref="HabaneroArgumentException">This error is thrown when an invalid parameter is given</exception> ///<exception cref="TargetInvocationException">This error is thrown when there is an error in finding the property on the supplied object</exception> ///<exception cref="Exception">This is a general exception that is thrown if there is an error in retrieving the value.</exception> public static void SetInternalPropertyValue(object obj, string propertyName, object value) { if (obj == null) { throw new HabaneroArgumentException("obj"); } if (String.IsNullOrEmpty(propertyName)) { throw new HabaneroArgumentException("propertyName"); } Type type = obj.GetType(); string className = type.Name; try { PropertyInfo propInfo = GetPrivatePropertyInfo(type, propertyName); if (propInfo == null) { throw new TargetInvocationException(new Exception( String.Format("Virtual property set for '{0}' does not exist for object of type '{1}'.", propertyName, className))); } SetPropValue(obj, propInfo, value); } catch (TargetInvocationException ex) { _log.Log(String.Format("Error setting internal property '{0}' for object of type '{1}'" + Environment.NewLine + "{2}", propertyName, className, ExceptionUtilities.GetExceptionString(ex.InnerException, 8, true)), LogCategory.Exception); throw ex.InnerException; } }
/// <summary> /// Loads a data reader /// </summary> /// <param name="selectSql">The sql statement object</param> /// <returns>Returns an IDataReader object</returns> /// <exception cref="DatabaseReadException">Thrown when an error /// occurred while setting up the data reader. Also sends error /// output to the log.</exception> public virtual IDataReader LoadDataReader(ISqlStatement selectSql) { if (selectSql == null) { throw new DatabaseConnectionException ("The sql statement object " + "that has been passed to LoadDataReader() is null."); } IDbConnection con = null; try { con = GetOpenConnectionForReading(); var cmd = CreateCommand(con); selectSql.SetupCommand(cmd); SetupReadTransaction(cmd); return(cmd.ExecuteReader(CommandBehavior.CloseConnection)); } catch (Exception ex) { Log.Log ("Error reading from database : " + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 10, true), LogCategory.Exception); Log.Log("Sql: " + selectSql, LogCategory.Exception); Console.Out.WriteLine ("Error reading from database : " + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 10, true)); Console.Out.WriteLine("Sql: " + selectSql); throw new DatabaseReadException ("There was an error reading the database. Please contact your system administrator." + Environment.NewLine + selectSql.ToString() + Environment.NewLine, "The DataReader could not be filled with", ex, selectSql.ToString(), ErrorSafeConnectString()); } }
/// <summary> /// Either finds a closed connection and opens and returns it, /// or creates a new connection and returns that. Throws an /// exception and adds a message to the log if there is an /// error opening a connection. /// </summary> /// <returns>Returns a new IDbConnection object</returns> protected internal virtual IDbConnection GetOpenConnectionForReading() { try { lock (LockObject) { // looks for closed connections for reading because open // connections could have readers still associated with them. foreach (var dbConnection in _connections) { //if (dbConnection.State != ConnectionState.Closed) continue; if (!dbConnection.Available) { continue; } dbConnection.Open(); return(dbConnection); } var newDbConnection = this.NewConnection; newDbConnection.Open(); _connections.Add(new ManagedConnection(newDbConnection)); return(newDbConnection); } } catch (Exception ex) { Log.Log ("Error opening connection to db : " + ex.GetType().Name + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 8, true), LogCategory.Exception); throw; } }
/// <summary> /// Returns the first closed connection available or returns a /// new connection object. Throws an exception and adds a message /// to the log if there is an error opening a connection. /// </summary> /// <returns>Returns a new IDbConnection object</returns> public IDbConnection GetConnection() { try { lock (LockObject) { foreach (var dbConnection in _connections) { //if (dbConnection.State == ConnectionState.Closed) if (dbConnection.Available) { return(dbConnection); } } var newDbConnection = this.NewConnection; _connections.Add(new ManagedConnection(newDbConnection)); return(newDbConnection); } } catch (Exception ex) { Log.Log ("Error opening connection to db : " + ex.GetType().Name + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 8, true), LogCategory.Exception); throw new DatabaseConnectionException ("An error occurred while attempting " + "to connect to the database.", ex); } }
/// <summary> /// Executes a parameterless method of an object using reflection /// </summary> /// <param name="obj">The object owning the method</param> /// <param name="methodName">The name of the method</param> /// <param name="arguments">The arguments for the private method</param> public static object ExecutePrivateMethod(object obj, string methodName, params object[] arguments) { if (obj == null) { throw new HabaneroArgumentException("obj"); } if (String.IsNullOrEmpty(methodName)) { throw new HabaneroArgumentException("methodName"); } Type type = obj.GetType(); string className = type.Name; try { MethodInfo methodInfo = GetPrivateMethodInfo(type, methodName); if (methodInfo == null) { throw new TargetInvocationException( new Exception(String.Format( "Virtual method call for '{0}' does not exist for object of type '{1}'.", methodName, className))); } return(methodInfo.Invoke(obj, arguments)); } catch (TargetInvocationException ex) { _log.Log(String.Format("Error calling private method '{0}' for object of type '{1}'" + Environment.NewLine + "{2}", methodName, className, ExceptionUtilities.GetExceptionString(ex.InnerException, 8, true)), LogCategory.Exception); throw ex.InnerException; } }
/// <summary> /// Executes the transactions and rolls back in the event of an error. /// </summary> private void Execute() { try { foreach (ITransactional transaction in _originalTransactions) { ExecuteTransactionToDataSource(transaction); } } catch (Exception ex) { Log.Log( "Error executing transaction: " + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 4, true), LogCategory.Exception); try { TryRollback(); } catch (Exception rollBackException) { Log.Log ("Error rolling back transaction: " + Environment.NewLine + ExceptionUtilities.GetExceptionString(rollBackException, 4, true), LogCategory.Exception); } UpdateTransactionsAsRolledBack(); throw; } }
/// <summary> /// Notifies the user of an exception that has occurred, by adding /// the error text to the console /// </summary> /// <param name="ex">The exception</param> /// <param name="furtherMessage">Any further error messages</param> /// <param name="title">The title</param> public void Notify(Exception ex, string furtherMessage, string title) { _exceptionMessage = "Error: " + furtherMessage + "Further details: " + ExceptionUtilities.GetExceptionString(ex, 0, true); System.Console.Out.WriteLine("Error: " + furtherMessage); System.Console.Out.WriteLine("Further details: " + ExceptionUtilities.GetExceptionString(ex, 0, true)); }
/// <summary> /// Sets up the panel that shows the error details /// </summary> private void SetFullDetailsPanel() { _fullDetail = _controlFactory.CreatePanel(); _fullDetail.Text = "Error Detail"; _errorDetails = _controlFactory.CreateTextBox(); _errorDetails.Text = ExceptionUtilities.GetExceptionString(_exception, 0, false); _errorDetails.Multiline = true; _errorDetails.ScrollBars = ScrollBars.Both; _showStackTrace = _controlFactory.CreateCheckBox(); _showStackTrace.Text = "&Show stack trace"; _showStackTrace.CheckedChanged += ShowStackTraceClicked; var manager = _controlFactory.CreateBorderLayoutManager(_fullDetail); manager.AddControl(_errorDetails, BorderLayoutManager.Position.Centre); var chkPanel = _controlFactory.CreatePanel(); var vgap = LayoutManager.DefaultGapSize + LayoutManager.DefaultBorderSize; if (GlobalUIRegistry.UIStyleHints != null) { vgap = GlobalUIRegistry.UIStyleHints.LayoutHints.DefaultVerticalGap + GlobalUIRegistry.UIStyleHints.LayoutHints.DefaultBorderSize; } chkPanel.Height = _showStackTrace.Height + 2 * vgap; var chkManager = _controlFactory.CreateBorderLayoutManager(chkPanel); chkManager.AddControl(_showStackTrace, BorderLayoutManager.Position.West); manager.AddControl(chkPanel, BorderLayoutManager.Position.South); }
/// <summary> /// Launches the application, initialising the logger, the database /// configuration and connection, the class definitions, the exception /// notifier and the synchronisation controller. This method also /// carries out any version upgrades using the /// IApplicationVersionUpgrader, if specified. /// </summary> /// <returns>Returns true if launched successfully, false if not. A /// failed launch will result in error messages being sent to the log /// with further information about the failure.</returns> public virtual bool Startup() { IHabaneroLogger log = null; try { SetupApplicationNameAndVersion(); SetupLogging(); SetupExceptionNotifier(); log = GlobalRegistry.LoggerFactory.GetLogger("HabaneroApp"); LogAppStartingInfo(log); SetupDatabaseConnection(); SetupSettings(); SetupClassDefs(); Upgrade(); } catch (Exception ex) { string errorMessage = "There was a problem starting the application."; if (log != null) { log.Log("---------------------------------------------" + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 0, true), LogCategory.Exception); errorMessage += " Please look at the log file for details of the problem."; } if (GlobalRegistry.UIExceptionNotifier != null) { GlobalRegistry.UIExceptionNotifier.Notify( new UserException(errorMessage, ex), "Problem in Startup:", "Problem in Startup"); } return(false); } return(true); }
/// <summary> /// Executes a collection of sql commands that returns no result set /// and takes no parameters, using the provided connection. /// This method can be used effectively where the database vendor /// supports the execution of several sql statements in one /// ExecuteNonQuery. However, for database vendors like Microsoft /// Access and MySql, the sql statements will need to be split up /// and executed as separate transactions. /// </summary> /// <param name="statements">A valid sql statement object (typically "insert", /// "update" or "delete"). Note_ that this assumes that the /// sqlCommand is not a stored procedure.</param> /// <param name="transaction">A valid transaction object in which the /// sql must be executed, or null</param> /// <returns>Returns the number of rows affected</returns> /// <exception cref="DatabaseWriteException">Thrown if there is an /// error writing to the database. Also outputs error messages to the log. /// </exception> /// <future> /// In future override this method with methods that allow you to /// pass in stored procedures and parameters. /// </future> public virtual int ExecuteSql(IEnumerable <ISqlStatement> statements, IDbTransaction transaction) { var inTransaction = transaction != null; ArgumentValidationHelper.CheckArgumentNotNull(statements, "statements"); IDbConnection con = null; try { con = GetOpenConnection(transaction); if (transaction == null) { transaction = BeginTransaction(con); } var totalRowsAffected = ExecuteSqlInternal(statements, con, transaction); if (!inTransaction) { transaction.Commit(); } return(totalRowsAffected); } catch (Exception ex) { Log.Log ("Error writing to database : " + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 10, true), LogCategory.Exception); Log.Log("Sql: " + statements, LogCategory.Exception); if (transaction != null) { transaction.Rollback(); } throw new DatabaseWriteException ("There was an error writing to the database. Please contact your system administrator." + Environment.NewLine + "The command executeNonQuery could not be completed. :" + statements, "The command executeNonQuery could not be completed.", ex, statements.ToString(), ErrorSafeConnectString()); } finally { if (!inTransaction) { if (con != null && con.State != ConnectionState.Closed) { con.Close(); } } } }
/// <summary> /// Executes a stored proc with the params given using the timeout length given. /// </summary> /// <param name="procName">The stored proc name</param> /// <param name="params">The parameters to pass in</param> /// <param name="timeout">The timeout in seconds</param> /// <returns>A scalar result</returns> public int ExecuteStoredProcNonQuery(string procName, IEnumerable <Param> @params, int timeout) { ArgumentValidationHelper.CheckArgumentNotNull(procName, "procName"); ArgumentValidationHelper.CheckArgumentNotNull(@params, "params"); IDbConnection con = null; try { con = OpenConnection; var cmd = CreateCommand(con); cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = procName; if (timeout > 0) { cmd.CommandTimeout = timeout; } foreach (var param in @params) { var dbParam = cmd.CreateParameter(); dbParam.DbType = param.DbType; dbParam.ParameterName = param.ParamName; dbParam.Value = param.ParamValue; cmd.Parameters.Add(dbParam); } return(cmd.ExecuteNonQuery()); } catch (Exception ex) { Log.Log ("Error executing stored procedure : " + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 10, true), LogCategory.Exception); Log.Log("Stored procedure: " + procName, LogCategory.Exception); throw new DatabaseWriteException ("There was an error writing to the database. Please contact your system administrator." + Environment.NewLine + "A stored procedure command could not be completed.", "A stored procedure command could not be completed: " + procName, ex, procName + String.Join(", ", @params), ErrorSafeConnectString()); } finally { if (con != null && con.State != ConnectionState.Closed) { con.Close(); } } }
/// <summary> /// Sets up the panel that shows the error details /// </summary> private void SetFullDetailsPanel() { _fullDetailPanel = new PanelVWG(); _fullDetailPanel.Text = "Error Detail"; _fullDetailPanel.Height = FULL_DETAIL_HEIGHT; _fullDetailPanel.Visible = false; _errorDetails = new TextBoxVWG(); _errorDetails.Text = ExceptionUtilities.GetExceptionString(_exception, 0, false); _errorDetails.Multiline = true; _errorDetails.ScrollBars = Gizmox.WebGUI.Forms.ScrollBars.Both; _showStackTrace = new CheckBoxVWG(); _showStackTrace.Text = "&Show stack trace"; _showStackTrace.CheckedChanged += ShowStackTraceClicked; BorderLayoutManager detailsManager = new BorderLayoutManagerVWG(_fullDetailPanel, GlobalUIRegistry.ControlFactory); detailsManager.AddControl(_errorDetails, BorderLayoutManager.Position.Centre); detailsManager.AddControl(_showStackTrace, BorderLayoutManager.Position.South); }
/// <summary> /// Commits all the successfully executed statements to the datasource. /// 2'nd phase of a 2 phase database commit and /// marks all the ITransactional objects as committed. /// </summary> private void Commit() { try { _commitSuccess = CommitToDatasource(); } catch { try { TryRollback(); } catch (Exception rollBackException) { Log.Log ("Error rolling back transaction: " + Environment.NewLine + ExceptionUtilities.GetExceptionString(rollBackException, 4, true), LogCategory.Exception); } throw; } if (_commitSuccess) { UpdateTransactionsAsCommited(); } else { try { TryRollback(); } catch (Exception rollBackException) { Log.Log ("Error rolling back transaction: " + Environment.NewLine + ExceptionUtilities.GetExceptionString(rollBackException, 4, true), LogCategory.Exception); throw; } UpdateTransactionsAsRolledBack(); } }
private void EmailErrorClickHandler(object sender, EventArgs e) { try { string emailTo = GlobalRegistry.Settings.GetString("EMAIL_TO"); string[] emailAddresses = emailTo.Split(new char[] { ';' }); string emailFrom = GlobalRegistry.Settings.GetString("EMAIL_FROM"); string emailContent = ExceptionUtilities.GetExceptionString(_exception, 0, true); EmailSender emailSender = new EmailSender(emailAddresses, emailFrom, _exception.Source, emailContent, ""); //Todo : check Send Authenticated for security purposes? emailSender.SmtpServerHost = GlobalRegistry.Settings.GetString("SMTP_SERVER"); string port = GlobalRegistry.Settings.GetString("SMTP_SERVER_PORT"); if (!String.IsNullOrEmpty(port)) { emailSender.SmtpServerPort = Convert.ToInt32(port); } bool enableSSL = GlobalRegistry.Settings.GetBoolean("SMTP_ENABLE_SSL"); emailSender.EnableSSL = enableSSL; //string authUsername = GlobalRegistry.Settings.GetString("SMTP_AUTH_USERNAME"); //string authPassword = GlobalRegistry.Settings.GetString("SMTP_AUTH_PASSWORD"); //if (!String.IsNullOrEmpty(authPassword)) //{ // authPassword = Encryption.Decrypt(authPassword); //} //if (!String.IsNullOrEmpty(authUsername)) //{ // emailSender.SendAuthenticated(authUsername, authPassword); //} //else //{ emailSender.Send(); //} } catch (Exception ex) { MessageBox.Show("The error message was not sent due to the following error : " + Environment.NewLine + ex.Message); } }
private void EmailErrorClickHandler(object sender, EventArgs e) { try { string userDescription = ""; ErrorDescriptionForm errorDescriptionForm = new ErrorDescriptionForm(); errorDescriptionForm.Closing += delegate { userDescription = errorDescriptionForm.ErrorDescriptionTextBox.Text; }; errorDescriptionForm.ShowDialog(this); IDictionary dictionary = GetEmailErrorSettings(); string exceptionString = ExceptionUtilities.GetExceptionString(_exception, 0, true); if (!string.IsNullOrEmpty(userDescription)) { exceptionString = "User Description : " + Environment.NewLine + userDescription + Environment.NewLine + " - Exception : " + exceptionString; } if (dictionary != null) { try { SendErrorMessage(dictionary, exceptionString); return; } catch (Exception ex) { exceptionString += Environment.NewLine + " - Error sending mail via smtp: " + Environment.NewLine + ex.Message; } } System.Diagnostics.Process.Start("mailto:?subject=" + _exception.Source + "&body=" + exceptionString); } catch (Exception ex) { MessageBox.Show("The error message was not sent due to the following error : " + Environment.NewLine + ex.Message); } }
/// <summary> /// Loads data from the database into a DataTable object, using the /// sql statement object provided /// </summary> /// <param name="selectSql">The sql statement object</param> /// <param name="strSearchCriteria">The search criteria as a string /// to append</param> /// <param name="strOrderByCriteria">The order by criteria as a string /// to append</param> /// <returns>Returns a DataTable object</returns> /// <exception cref="DatabaseReadException">Thrown if there is an /// error reading the database. Also outputs error messages to the log. /// </exception> public DataTable LoadDataTable(ISqlStatement selectSql, string strSearchCriteria, string strOrderByCriteria) { //It was chosen to use a datareader to fill the DataTable instead of using an // adapter because the data adapter approach requires creating a different adapter depending on the // database type. This is understandable but for simple loading of a datatable without all the additional // schema data it is unneccessary. // It could however be easily achieved since there is a physical instance of a database connection object // per database type that inherit from this class e.g. DatabaseConnectionMySQL. if (selectSql == null) { throw new ArgumentNullException("selectSql"); } IDbConnection con = null; try { con = GetOpenConnectionForReading(); IDbCommand cmd = CreateCommand(con); selectSql.SetupCommand(cmd); DataTable dt; using (IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { dt = GetDataTable(reader); reader.Close(); } return(dt); } catch (Exception ex) { Log.Log ("Error in LoadDataTable:" + Environment.NewLine + ExceptionUtilities.GetExceptionString(ex, 8, true), LogCategory.Exception); Log.Log("Sql string: " + selectSql, LogCategory.Exception); throw new DatabaseReadException ("There was an error reading the database. Please contact your system administrator.", "The DataReader could not be filled with", ex, selectSql.ToString(), ErrorSafeConnectString()); } }
/// <summary> /// A handler to respond when the "OK" button has been pressed. /// All changes are committed to the database and the dialog is closed. /// </summary> /// <param name="sender">The object that notified of the event</param> /// <param name="e">Attached arguments regarding the event</param> private void OKButtonHandler(object sender, EventArgs e) { try { _panelInfo.ApplyChangesToBusinessObject(); ITransactionCommitter committer = CreateSaveTransaction(); committer.CommitTransaction(); DialogResult = DialogResult.OK; if (_postObjectEditAction != null) { _postObjectEditAction(this._bo, false); } _panelInfo.BusinessObject = null; SafeCloseForm(); } catch (Exception ex) { log.Error(ExceptionUtilities.GetExceptionString(ex, 0, true)); GlobalRegistry.UIExceptionNotifier.Notify(ex, "There was a problem saving for the following reason(s):", "Saving Problem"); } }
/// <summary> /// Toggles the showing of the stack trace in the error details /// </summary> private void ShowStackTraceClicked(object sender, EventArgs e) { _errorDetails.Text = ExceptionUtilities.GetExceptionString(_exception, 0, _showStackTrace.Checked); }