private static void PersistToDataStore(IAppError appError) { if (appError.AppErrorId == int.MinValue) { using (SqlConnection cn = SqlDataProvider.GetDbConnection()) { using (SqlCommand cmd = GetCommandErrorInsert(appError, cn)) { cn.Open(); cmd.ExecuteNonQuery(); int id = Convert.ToInt32(cmd.Parameters["@Identity"].Value, System.Globalization.NumberFormatInfo.CurrentInfo); if (appError.AppErrorId != id) { appError.AppErrorId = id; } } } } else { throw new DataException("Cannot save a previously existing application error to the data store."); } }
private void ConfigureControls() { imgGspLogo.ImageUrl = Util.GetUrl("/images/gsp_logo_313x75.png"); hlSiteAdmin.NavigateUrl = Util.GetUrl(PageId.admin_general); hlHome.NavigateUrl = Util.GetCurrentPageUrl(); // The global error handler in Gallery.cs should have, just prior to transferring to this page, placed the original // error in the HttpContext Items bag. If the Show Error Details setting is enabled, grab this info and display it. if (Configuration.ConfigManager.GetGalleryServerProConfigSection().Core.ShowErrorDetails) { pErrorDtl2.Visible = false; lblSeparator.Visible = false; hlSiteAdmin.Visible = false; IAppError error = System.Web.HttpContext.Current.Items["CurrentAppError"] as IAppError; if (error != null) { this.Page.Header.Controls.Add(new LiteralControl(error.CssStyles)); litErrorDetails.Text = error.ToHtml(); } else { litErrorDetails.Text = "<p class='gsp_msgwarning'>Error information missing from HttpContext Items bag. Please submit bug report to the <a href='http://www.galleryserverpro.com/forum/'>Gallery Server Pro forum</a>.</p>"; } } }
private static DataRow AddDataRow(DataRow dr, IAppError err, ErrorItem item) { dr[0] = err.AppErrorId; dr[1] = err.ToHtmlName(item); dr[2] = err.ToHtmlValue(item); return(dr); }
/// <summary> /// Persist the specified application error to the data store. Return the ID assigned to the error. Does not save if database /// is SQL Server 2000 or earlier; instead it just returns int.MinValue. (SQL Server 2000 has a max row length of 8000 bytes, /// and the error data very likely requires more than this.) /// </summary> /// <param name="appError">An instance of <see cref="IAppError" /> to persist to the data store. Must be a new error /// (AppErrorId == int.MinValue) that has not previously been saved to the data store.</param> /// <returns>Return the ID assigned to the error. The ID is also assigned to the AppErrorId property of <paramref name="appError"/>.</returns> /// <exception cref="DataException">Thrown when <see cref="IAppError.AppErrorId"/> is greater than <see cref="int.MinValue"/>.</exception> internal static int Save(IAppError appError) { if (Util.GetSqlVersion() < SqlVersion.Sql2005) return int.MinValue; PersistToDataStore(appError); return appError.AppErrorId; }
/// <summary> /// Persist the specified application error to the data store. Return the ID assigned to the error. Does not save if database /// is SQL Server 2000 or earlier; instead it just returns int.MinValue. (SQL Server 2000 has a max row length of 8000 bytes, /// and the error data very likely requires more than this.) /// </summary> /// <param name="appError">An instance of <see cref="IAppError" /> to persist to the data store. Must be a new error /// (AppErrorId == int.MinValue) that has not previously been saved to the data store.</param> /// <returns>Return the ID assigned to the error. The ID is also assigned to the AppErrorId property of <paramref name="appError"/>.</returns> /// <exception cref="DataException">Thrown when <see cref="IAppError.AppErrorId"/> is greater than <see cref="int.MinValue"/>.</exception> internal static int Save(IAppError appError) { if (Util.GetSqlVersion() < SqlVersion.Sql2005) { return(int.MinValue); } PersistToDataStore(appError); return(appError.AppErrorId); }
/// <summary> /// Determines whether details about the <paramref name="error" /> can be shown to the user. When the app is in debug /// mode (debug = true in web.config), then always show the error details. If debug = false, then use the ShowErrorDetails setting. /// </summary> /// <param name="error">The error.</param> /// <returns></returns> private static bool ShouldShowErrorDetails(IAppError error) { bool isInDebugMode = System.Web.HttpContext.Current.IsDebuggingEnabled; bool showErrorDetailsSettingFromConfig = false; if ((error != null) && (error.GalleryId > Int32.MinValue)) { try { // We may get an error trying to load the setting from the database. In this case, just ignore the error and use the default // value. showErrorDetailsSettingFromConfig = Factory.LoadGallerySetting(error.GalleryId).ShowErrorDetails; } catch { } } return (isInDebugMode || showErrorDetailsSettingFromConfig); }
private static SqlCommand GetCommandErrorInsert(IAppError appError) { //INSERT [gs_AppError] // (FKGalleryId, TimeStamp, ExceptionType, Message, Source, TargetSite, StackTrace, ExceptionData, InnerExType, // InnerExMessage, InnerExSource, InnerExTargetSite, InnerExStackTrace, InnerExData, Url, // FormVariables, Cookies, SessionVariables, ServerVariables) //VALUES (@GalleryId, @TimeStamp, @ExceptionType, @Message, @Source, @TargetSite, @StackTrace, @ExceptionData, @InnerExType, // @InnerExMessage, @InnerExSource, @InnerExTargetSite, @InnerExStackTrace, @InnerExData, @Url, // @FormVariables, @Cookies, @SessionVariables, @ServerVariables) DataStore dataStoreConfig = ConfigManager.GetGalleryServerProConfigSection().DataStore; SqlCommand cmd = new SqlCommand(Util.GetSqlName("gs_AppErrorInsert"), SqlDataProvider.GetDbConnection()); cmd.CommandType = CommandType.StoredProcedure; const int nvarcharMAX = -1; // The parameter length mapped to nvarchar(max) definitions cmd.Parameters.Add("@GalleryId", SqlDbType.Int).Value = appError.GalleryId; cmd.Parameters.Add("@TimeStamp", SqlDbType.DateTime).Value = appError.TimeStamp; cmd.Parameters.Add("@ExceptionType", SqlDbType.NVarChar, dataStoreConfig.ErrorExTypeLength).Value = appError.ExceptionType; cmd.Parameters.Add("@Message", SqlDbType.NVarChar, dataStoreConfig.ErrorExMsgLength).Value = appError.Message; cmd.Parameters.Add("@Source", SqlDbType.NVarChar, dataStoreConfig.ErrorExSourceLength).Value = appError.Source; cmd.Parameters.Add("@TargetSite", SqlDbType.NVarChar, nvarcharMAX).Value = appError.TargetSite; cmd.Parameters.Add("@StackTrace", SqlDbType.NVarChar, nvarcharMAX).Value = appError.StackTrace; cmd.Parameters.Add("@ExceptionData", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.ExceptionData); cmd.Parameters.Add("@InnerExType", SqlDbType.NVarChar, dataStoreConfig.ErrorExTypeLength).Value = appError.InnerExType; cmd.Parameters.Add("@InnerExMessage", SqlDbType.NVarChar, dataStoreConfig.ErrorExMsgLength).Value = appError.InnerExMessage; cmd.Parameters.Add("@InnerExSource", SqlDbType.NVarChar, dataStoreConfig.ErrorExSourceLength).Value = appError.InnerExSource; cmd.Parameters.Add("@InnerExTargetSite", SqlDbType.NVarChar, nvarcharMAX).Value = appError.InnerExTargetSite; cmd.Parameters.Add("@InnerExStackTrace", SqlDbType.NVarChar, nvarcharMAX).Value = appError.InnerExStackTrace; cmd.Parameters.Add("@InnerExData", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.InnerExData); cmd.Parameters.Add("@Url", SqlDbType.NVarChar, dataStoreConfig.ErrorUrlLength).Value = appError.Url; cmd.Parameters.Add("@FormVariables", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.FormVariables); cmd.Parameters.Add("@Cookies", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.Cookies); cmd.Parameters.Add("@SessionVariables", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.SessionVariables); cmd.Parameters.Add("@ServerVariables", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.ServerVariables); SqlParameter prm = new SqlParameter("@Identity", SqlDbType.Int, 0, "AppErrorId"); prm.Direction = ParameterDirection.Output; cmd.Parameters.Add(prm); return(cmd); }
/// <summary> /// Sends an e-mail containing details about the <paramref name="appError" /> to all users who are configured to receive e-mail /// notifications in the specified <paramref name="gallerySettings" /> and who have valid e-mail addresses. (That is, e-mails are /// sent to users identified in the property <see cref="IGallerySettings.UsersToNotifyWhenErrorOccurs" />.) A list of usernames /// of those were were notified is returned. No e-mails are sent to any usernames in <paramref name="usersWhoWereAlreadyNotified" />. /// </summary> /// <param name="appError">The application error to be sent to users.</param> /// <param name="gallerySettings">The gallery settings containing the e-mail configuration data and list of users to be notified. /// The users are identified in the <see cref="IGallerySettings.UsersToNotifyWhenErrorOccurs" /> property.</param> /// <param name="usersWhoWereAlreadyNotified">The users who were previously notified about the <paramref name="appError" />.</param> /// <returns>Returns a list of usernames of those were were notified during execution of this function.</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="appError" /> or <paramref name="gallerySettings" /> /// is null.</exception> private static List <String> SendMail(IAppError appError, IGallerySettings gallerySettings, List <String> usersWhoWereAlreadyNotified) { #region Validation if (appError == null) { throw new ArgumentNullException("appError"); } if (gallerySettings == null) { throw new ArgumentNullException("gallerySettings"); } #endregion if (usersWhoWereAlreadyNotified == null) { usersWhoWereAlreadyNotified = new List <string>(); } List <String> notifiedUsers = new List <string>(); //If email reporting has been turned on, send detailed error report. if (!gallerySettings.SendEmailOnError) { return(notifiedUsers); } MailAddress emailSender = new MailAddress(gallerySettings.EmailFromAddress, gallerySettings.EmailFromName); foreach (IUserAccount user in gallerySettings.UsersToNotifyWhenErrorOccurs) { if (!usersWhoWereAlreadyNotified.Contains(user.UserName)) { if (SendMail(appError, user, gallerySettings, emailSender)) { notifiedUsers.Add(user.UserName); } } } return(notifiedUsers); }
/// <summary> /// Sends an e-mail containing details about the <paramref name="appError" /> to all users who are configured to receive error /// notifications in the gallery identified by <see cref="IAppError.GalleryId" />. If the error is not associated with a particular /// gallery (that is, <see cref="IAppError.GalleryId" /> == <see cref="Int32.MinValue" />, then e-mails are sent to users in all /// galleries who are configured to receive e-mailed error reports. The property <see cref="IGallerySettings.UsersToNotifyWhenErrorOccurs" /> /// defines this list of users. /// </summary> /// <param name="appError">The application error to be sent to users.</param> /// <param name="gallerySettingsCollection">The settings for all galleries. If the <paramref name="appError" /> is associated with /// a particular gallery, then only the settings for that gallery are used by this function; otherwise users in all galleries are /// notified.</param> /// <exception cref="ArgumentNullException">Thrown when <paramref name="appError" /> or <paramref name="gallerySettingsCollection" /> /// is null.</exception> private static void SendEmail(IAppError appError, IGallerySettingsCollection gallerySettingsCollection) { #region Validation if (appError == null) { throw new ArgumentNullException("appError"); } if (gallerySettingsCollection == null) { throw new ArgumentNullException("gallerySettingsCollection"); } // HACK: We don't want to send en email for INFO events. Until this logging API can be properly refactored to handle non-error // types, we just check the message here and skip the email if necessary. if (appError.Message.StartsWith("INFO (not an error):", StringComparison.OrdinalIgnoreCase)) { return; } #endregion if (appError.GalleryId > int.MinValue) { // Use settings from the gallery associated with the error. IGallerySettings gallerySettings = gallerySettingsCollection.FindByGalleryId(appError.GalleryId); if (gallerySettings != null) { SendMail(appError, gallerySettingsCollection.FindByGalleryId(appError.GalleryId), null); } } else { // This is an application-wide error, so loop through every gallery and notify all users, making sure we don't notify anyone more than once. List <String> notifiedUsers = new List <string>(); foreach (IGallerySettings gallerySettings in gallerySettingsCollection) { notifiedUsers.AddRange(SendMail(appError, gallerySettings, notifiedUsers)); } } }
/// <summary> /// Compares the current instance with another object of the same type. /// </summary> /// <param name="obj">An object to compare with this instance.</param> /// <returns> /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than <paramref name="obj"/>. Zero This instance is equal to <paramref name="obj"/>. Greater than zero This instance is greater than <paramref name="obj"/>. /// </returns> /// <exception cref="T:System.ArgumentException"> /// <paramref name="obj"/> is not the same type as this instance. </exception> public int CompareTo(object obj) { if (obj == null) { return(-1); } else { IAppError other = obj as IAppError; if (other != null) { return(-this.TimeStamp.CompareTo(other.TimeStamp)); } else { return(-1); } } }
/// <summary> /// Determines whether details about the <paramref name="error" /> can be shown to the user. When the app is in debug /// mode (debug = true in web.config), then always show the error details. If debug = false, then use the ShowErrorDetails setting. /// </summary> /// <param name="error">The error.</param> /// <returns></returns> private static bool ShouldShowErrorDetails(IAppError error) { bool isInDebugMode = System.Web.HttpContext.Current.IsDebuggingEnabled; bool showErrorDetailsSettingFromConfig = false; if ((error != null) && (error.GalleryId > Int32.MinValue)) { try { // We may get an error trying to load the setting from the database. In this case, just ignore the error and use the default // value. showErrorDetailsSettingFromConfig = Factory.LoadGallerySetting(error.GalleryId).ShowErrorDetails; } catch { } } return(isInDebugMode || showErrorDetailsSettingFromConfig); }
private static SqlCommand GetCommandErrorInsert(IAppError appError, SqlConnection cn) { //INSERT [gs_AppError] // (FKGalleryId, TimeStamp, ExceptionType, Message, Source, TargetSite, StackTrace, ExceptionData, InnerExType, // InnerExMessage, InnerExSource, InnerExTargetSite, InnerExStackTrace, InnerExData, Url, // FormVariables, Cookies, SessionVariables, ServerVariables) //VALUES (@GalleryId, @TimeStamp, @ExceptionType, @Message, @Source, @TargetSite, @StackTrace, @ExceptionData, @InnerExType, // @InnerExMessage, @InnerExSource, @InnerExTargetSite, @InnerExStackTrace, @InnerExData, @Url, // @FormVariables, @Cookies, @SessionVariables, @ServerVariables) SqlCommand cmd = new SqlCommand(Util.GetSqlName("gs_AppErrorInsert"), cn); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@GalleryId", SqlDbType.Int).Value = appError.GalleryId; cmd.Parameters.Add("@TimeStamp", SqlDbType.DateTime).Value = appError.Timestamp; cmd.Parameters.Add("@ExceptionType", SqlDbType.NVarChar, DataConstants.ErrorExTypeLength).Value = appError.ExceptionType; cmd.Parameters.Add("@Message", SqlDbType.NVarChar, DataConstants.ErrorExMsgLength).Value = appError.Message; cmd.Parameters.Add("@Source", SqlDbType.NVarChar, DataConstants.ErrorExSourceLength).Value = appError.Source; cmd.Parameters.Add("@TargetSite", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = appError.TargetSite; cmd.Parameters.Add("@StackTrace", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = appError.StackTrace; cmd.Parameters.Add("@ExceptionData", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.ExceptionData); cmd.Parameters.Add("@InnerExType", SqlDbType.NVarChar, DataConstants.ErrorExTypeLength).Value = appError.InnerExType; cmd.Parameters.Add("@InnerExMessage", SqlDbType.NVarChar, DataConstants.ErrorExMsgLength).Value = appError.InnerExMessage; cmd.Parameters.Add("@InnerExSource", SqlDbType.NVarChar, DataConstants.ErrorExSourceLength).Value = appError.InnerExSource; cmd.Parameters.Add("@InnerExTargetSite", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = appError.InnerExTargetSite; cmd.Parameters.Add("@InnerExStackTrace", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = appError.InnerExStackTrace; cmd.Parameters.Add("@InnerExData", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.InnerExData); cmd.Parameters.Add("@Url", SqlDbType.NVarChar, DataConstants.ErrorUrlLength).Value = appError.Url; cmd.Parameters.Add("@FormVariables", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.FormVariables); cmd.Parameters.Add("@Cookies", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.Cookies); cmd.Parameters.Add("@SessionVariables", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.SessionVariables); cmd.Parameters.Add("@ServerVariables", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.ServerVariables); SqlParameter prm = new SqlParameter("@Identity", SqlDbType.Int, 0, "AppErrorId"); prm.Direction = ParameterDirection.Output; cmd.Parameters.Add(prm); return(cmd); }
public void DeleteAppError(int appErrorId) { IAppError appError = null; try { appError = Factory.GetAppErrors().FindById(appErrorId); bool isAuthorized = true; // If the error has a gallery ID (not all do), then check the user's permission. For those errors without a gallery ID, // just assume the user has permission, because there is no way to verify the user can delete this error. We could do something // that mostly works like verifying the user is a gallery admin for at least one gallery, but the function we are trying to // protect is deleting an error message, which is not that important to worry about. if (appError.GalleryId > int.MinValue) { isAuthorized = Utils.IsUserAuthorized(SecurityActions.AdministerSite | SecurityActions.AdministerGallery, RoleController.GetGalleryServerRolesForUser(), int.MinValue, appError.GalleryId, false); } if (isAuthorized) { GalleryServerPro.ErrorHandler.Error.Delete(appErrorId); HelperFunctions.PurgeCache(); } } catch (Exception ex) { if (appError != null) { AppErrorController.LogError(ex, appError.GalleryId); } else { AppErrorController.LogError(ex); } throw; } }
private static DataRow AddDataRow(DataRow dr, IAppError err, ErrorItem item) { dr[0] = err.AppErrorId; dr[1] = err.ToHtmlName(item); dr[2] = err.ToHtmlValue(item); return dr; }
public CourseService(IAppError errors, ICourseDataAccess dal) { this.errors = errors; this.dal = dal; }
private static SqlCommand GetCommandErrorInsert(IAppError appError) { //INSERT [gs_AppError] // (FKGalleryId, TimeStamp, ExceptionType, Message, Source, TargetSite, StackTrace, ExceptionData, InnerExType, // InnerExMessage, InnerExSource, InnerExTargetSite, InnerExStackTrace, InnerExData, Url, // FormVariables, Cookies, SessionVariables, ServerVariables) //VALUES (@GalleryId, @TimeStamp, @ExceptionType, @Message, @Source, @TargetSite, @StackTrace, @ExceptionData, @InnerExType, // @InnerExMessage, @InnerExSource, @InnerExTargetSite, @InnerExStackTrace, @InnerExData, @Url, // @FormVariables, @Cookies, @SessionVariables, @ServerVariables) DataStore dataStoreConfig = ConfigManager.GetGalleryServerProConfigSection().DataStore; SqlCommand cmd = new SqlCommand(Util.GetSqlName("gs_AppErrorInsert"), SqlDataProvider.GetDbConnection()); cmd.CommandType = CommandType.StoredProcedure; const int nvarcharMAX = -1; // The parameter length mapped to nvarchar(max) definitions cmd.Parameters.Add("@GalleryId", SqlDbType.Int).Value = appError.GalleryId; cmd.Parameters.Add("@TimeStamp", SqlDbType.DateTime).Value = appError.TimeStamp; cmd.Parameters.Add("@ExceptionType", SqlDbType.NVarChar, dataStoreConfig.ErrorExTypeLength).Value = appError.ExceptionType; cmd.Parameters.Add("@Message", SqlDbType.NVarChar, dataStoreConfig.ErrorExMsgLength).Value = appError.Message; cmd.Parameters.Add("@Source", SqlDbType.NVarChar, dataStoreConfig.ErrorExSourceLength).Value = appError.Source; cmd.Parameters.Add("@TargetSite", SqlDbType.NVarChar, nvarcharMAX).Value = appError.TargetSite; cmd.Parameters.Add("@StackTrace", SqlDbType.NVarChar, nvarcharMAX).Value = appError.StackTrace; cmd.Parameters.Add("@ExceptionData", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.ExceptionData); cmd.Parameters.Add("@InnerExType", SqlDbType.NVarChar, dataStoreConfig.ErrorExTypeLength).Value = appError.InnerExType; cmd.Parameters.Add("@InnerExMessage", SqlDbType.NVarChar, dataStoreConfig.ErrorExMsgLength).Value = appError.InnerExMessage; cmd.Parameters.Add("@InnerExSource", SqlDbType.NVarChar, dataStoreConfig.ErrorExSourceLength).Value = appError.InnerExSource; cmd.Parameters.Add("@InnerExTargetSite", SqlDbType.NVarChar, nvarcharMAX).Value = appError.InnerExTargetSite; cmd.Parameters.Add("@InnerExStackTrace", SqlDbType.NVarChar, nvarcharMAX).Value = appError.InnerExStackTrace; cmd.Parameters.Add("@InnerExData", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.InnerExData); cmd.Parameters.Add("@Url", SqlDbType.NVarChar, dataStoreConfig.ErrorUrlLength).Value = appError.Url; cmd.Parameters.Add("@FormVariables", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.FormVariables); cmd.Parameters.Add("@Cookies", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.Cookies); cmd.Parameters.Add("@SessionVariables", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.SessionVariables); cmd.Parameters.Add("@ServerVariables", SqlDbType.NVarChar, nvarcharMAX).Value = ErrorHandler.Error.Serialize(appError.ServerVariables); SqlParameter prm = new SqlParameter("@Identity", SqlDbType.Int, 0, "AppErrorId"); prm.Direction = ParameterDirection.Output; cmd.Parameters.Add(prm); return cmd; }
private static void SendEmail(IAppError appError) { //If email reporting has been turned on, send detailed error report. Core coreConfig = ConfigManager.GetGalleryServerProConfigSection().Core; if (!coreConfig.SendEmailOnError) { return; } MailAddress emailRecipient = new MailAddress(coreConfig.EmailToAddress, coreConfig.EmailToName); MailAddress emailSender = new MailAddress(coreConfig.EmailFromAddress, coreConfig.EmailFromName); try { using (MailMessage mail = new MailMessage(emailSender, emailRecipient)) { if (String.IsNullOrEmpty(appError.ExceptionType)) { mail.Subject = Resources.Email_Subject_When_No_Ex_Type_Present; } else { mail.Subject = String.Concat(Resources.Email_Subject_Prefix_When_Ex_Type_Present, " ", appError.ExceptionType); } mail.Body = appError.ToHtmlPage(); mail.IsBodyHtml = true; SmtpClient smtpClient = new SmtpClient(); smtpClient.EnableSsl = coreConfig.SendEmailUsingSsl; // Specify SMTP server if it's in galleryserverpro.config. The server might have been assigned via web.config, // so only update this if we have a config setting. if (!String.IsNullOrEmpty(coreConfig.SmtpServer)) { smtpClient.Host = coreConfig.SmtpServer; } // Specify port number if it's in galleryserverpro.config and it's not the default value of 25. The port // might have been assigned via web.config, so only update this if we have a config setting. int smtpServerPort; if (!Int32.TryParse(coreConfig.SmtpServerPort, out smtpServerPort)) { smtpServerPort = int.MinValue; } if ((smtpServerPort > 0) && (smtpServerPort != 25)) { smtpClient.Port = smtpServerPort; } smtpClient.Send(mail); } } catch (Exception ex2) { string errorMsg = String.Concat(ex2.GetType(), ": ", ex2.Message); if (ex2.InnerException != null) { errorMsg += String.Concat(" ", ex2.InnerException.GetType(), ": ", ex2.InnerException.Message); } appError.ExceptionData.Add(new KeyValuePair <string, string>(Resources.Cannot_Send_Email_Lbl, errorMsg)); } }
private static void PersistToDataStore(IAppError appError) { if (appError.AppErrorId == int.MinValue) { using (SqlConnection cn = SqlDataProvider.GetDbConnection()) { using (SqlCommand cmd = GetCommandErrorInsert(appError, cn)) { cn.Open(); cmd.ExecuteNonQuery(); int id = Convert.ToInt32(cmd.Parameters["@Identity"].Value, System.Globalization.NumberFormatInfo.CurrentInfo); if (appError.AppErrorId != id) appError.AppErrorId = id; } } } else { throw new DataException("Cannot save a previously existing application error to the data store."); } }
private static void SendEmail(IAppError appError) { //If email reporting has been turned on, send detailed error report. Core coreConfig = ConfigManager.GetGalleryServerProConfigSection().Core; if (!coreConfig.SendEmailOnError) return; MailAddress emailRecipient = new MailAddress(coreConfig.EmailToAddress, coreConfig.EmailToName); MailAddress emailSender = new MailAddress(coreConfig.EmailFromAddress, coreConfig.EmailFromName); try { using (MailMessage mail = new MailMessage(emailSender, emailRecipient)) { if (String.IsNullOrEmpty(appError.ExceptionType)) mail.Subject = Resources.Email_Subject_When_No_Ex_Type_Present; else mail.Subject = String.Concat(Resources.Email_Subject_Prefix_When_Ex_Type_Present, " ", appError.ExceptionType); mail.Body = appError.ToHtmlPage(); mail.IsBodyHtml = true; SmtpClient smtpClient = new SmtpClient(); smtpClient.EnableSsl = coreConfig.SendEmailUsingSsl; // Specify SMTP server if it's in galleryserverpro.config. The server might have been assigned via web.config, // so only update this if we have a config setting. if (!String.IsNullOrEmpty(coreConfig.SmtpServer)) { smtpClient.Host = coreConfig.SmtpServer; } // Specify port number if it's in galleryserverpro.config and it's not the default value of 25. The port // might have been assigned via web.config, so only update this if we have a config setting. int smtpServerPort; if (!Int32.TryParse(coreConfig.SmtpServerPort, out smtpServerPort)) smtpServerPort = int.MinValue; if ((smtpServerPort > 0) && (smtpServerPort != 25)) { smtpClient.Port = smtpServerPort; } smtpClient.Send(mail); } } catch (Exception ex2) { string errorMsg = String.Concat(ex2.GetType(), ": ", ex2.Message); if (ex2.InnerException != null) errorMsg += String.Concat(" ", ex2.InnerException.GetType(), ": ", ex2.InnerException.Message); appError.ExceptionData.Add(new KeyValuePair<string, string>(Resources.Cannot_Send_Email_Lbl, errorMsg)); } }
/// <summary> /// Persist the specified application error to the data store. Return the ID of the error. /// </summary> /// <param name="appError">The application error to persist to the data store.</param> /// <returns> /// Return the ID of the error. If this is a new error object and a new ID has been /// assigned, then this value has also been assigned to the ID property of the object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="appError" /> is null.</exception> public override int AppError_Save(IAppError appError) { if (appError == null) throw new ArgumentNullException("appError"); AppErrorDto aeDto = new AppErrorDto { FKGalleryId = appError.GalleryId, TimeStamp = appError.Timestamp, ExceptionType = appError.ExceptionType, Message = appError.Message, Source = appError.Source, TargetSite = appError.TargetSite, StackTrace = appError.StackTrace, ExceptionData = ErrorHandler.Error.Serialize(appError.ExceptionData), InnerExType = appError.InnerExType, InnerExMessage = appError.InnerExMessage, InnerExSource = appError.InnerExSource, InnerExTargetSite = appError.InnerExTargetSite, InnerExStackTrace = appError.InnerExStackTrace, InnerExData = ErrorHandler.Error.Serialize(appError.InnerExData), Url = appError.Url, FormVariables = ErrorHandler.Error.Serialize(appError.FormVariables), Cookies = ErrorHandler.Error.Serialize(appError.Cookies), SessionVariables = ErrorHandler.Error.Serialize(appError.SessionVariables), ServerVariables = ErrorHandler.Error.Serialize(appError.ServerVariables) }; using (GspContext ctx = new GspContext()) { ctx.AppErrors.Add(aeDto); ctx.SaveChanges(); appError.AppErrorId = aeDto.AppErrorId; return appError.AppErrorId; } }
/// <summary> /// Sends an e-mail containing details about the <paramref name="appError" /> to all users who are configured to receive e-mail /// notifications in the specified <paramref name="gallerySettings" /> and who have valid e-mail addresses. (That is, e-mails are /// sent to users identified in the property <see cref="IGallerySettings.UsersToNotifyWhenErrorOccurs" />.) A list of usernames /// of those were were notified is returned. No e-mails are sent to any usernames in <paramref name="usersWhoWereAlreadyNotified" />. /// </summary> /// <param name="appError">The application error to be sent to users.</param> /// <param name="gallerySettings">The gallery settings containing the e-mail configuration data and list of users to be notified. /// The users are identified in the <see cref="IGallerySettings.UsersToNotifyWhenErrorOccurs" /> property.</param> /// <param name="usersWhoWereAlreadyNotified">The users who were previously notified about the <paramref name="appError" />.</param> /// <returns>Returns a list of usernames of those were were notified during execution of this function.</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="appError" /> or <paramref name="gallerySettings" /> /// is null.</exception> private static List<String> SendMail(IAppError appError, IGallerySettings gallerySettings, List<String> usersWhoWereAlreadyNotified) { #region Validation if (appError == null) throw new ArgumentNullException("appError"); if (gallerySettings == null) throw new ArgumentNullException("gallerySettings"); #endregion if (usersWhoWereAlreadyNotified == null) { usersWhoWereAlreadyNotified = new List<string>(); } List<String> notifiedUsers = new List<string>(); //If email reporting has been turned on, send detailed error report. if (!gallerySettings.SendEmailOnError) { return notifiedUsers; } MailAddress emailSender = new MailAddress(gallerySettings.EmailFromAddress, gallerySettings.EmailFromName); foreach (IUserAccount user in gallerySettings.UsersToNotifyWhenErrorOccurs) { if (!usersWhoWereAlreadyNotified.Contains(user.UserName)) { if (SendMail(appError, user, gallerySettings, emailSender)) { notifiedUsers.Add(user.UserName); } } } return notifiedUsers; }
/// <summary> /// Sends an e-mail containing details about the <paramref name="appError" /> to the specified <paramref name="user" />. Returns /// <c>true</c> if the e-mail is successfully sent. /// </summary> /// <param name="appError">The application error to be sent to users.</param> /// <param name="user">The user to send the e-mail to.</param> /// <param name="gallerySettings">The gallery settings containing the e-mail configuration data.</param> /// <param name="emailSender">The account that that will appear in the "From" portion of the e-mail.</param> /// <returns>Returns <c>true</c> if the e-mail is successfully sent; otherwise <c>false</c>.</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="appError" />, <paramref name="user" />, /// <paramref name="gallerySettings" />, or <paramref name="emailSender" /> is null.</exception> private static bool SendMail(IAppError appError, IUserAccount user, IGallerySettings gallerySettings, MailAddress emailSender) { #region Validation if (appError == null) { throw new ArgumentNullException("appError"); } if (user == null) { throw new ArgumentNullException("user"); } if (gallerySettings == null) { throw new ArgumentNullException("gallerySettings"); } if (emailSender == null) { throw new ArgumentNullException("emailSender"); } #endregion bool emailWasSent = false; if (!IsValidEmail(user.Email)) { return(false); } MailAddress emailRecipient = new MailAddress(user.Email, user.UserName); try { using (MailMessage mail = new MailMessage(emailSender, emailRecipient)) { if (String.IsNullOrEmpty(appError.ExceptionType)) { mail.Subject = Resources.Email_Subject_When_No_Ex_Type_Present; } else { mail.Subject = String.Concat(Resources.Email_Subject_Prefix_When_Ex_Type_Present, " ", appError.ExceptionType); } mail.Body = appError.ToHtmlPage(); mail.IsBodyHtml = true; using (SmtpClient smtpClient = new SmtpClient()) { smtpClient.EnableSsl = gallerySettings.SendEmailUsingSsl; // Specify SMTP server if it is specified. The server might have been assigned via web.config, // so only update this if we have a config setting. if (!String.IsNullOrEmpty(gallerySettings.SmtpServer)) { smtpClient.Host = gallerySettings.SmtpServer; } // Specify port number if it is specified and it's not the default value of 25. The port // might have been assigned via web.config, so only update this if we have a config setting. int smtpServerPort; if (!Int32.TryParse(gallerySettings.SmtpServerPort, out smtpServerPort)) { smtpServerPort = int.MinValue; } if ((smtpServerPort > 0) && (smtpServerPort != 25)) { smtpClient.Port = smtpServerPort; } smtpClient.Send(mail); } emailWasSent = true; } } catch (Exception ex2) { string errorMsg = String.Concat(ex2.GetType(), ": ", ex2.Message); if (ex2.InnerException != null) { errorMsg += String.Concat(" ", ex2.InnerException.GetType(), ": ", ex2.InnerException.Message); } appError.ExceptionData.Add(new KeyValuePair <string, string>(Resources.Cannot_Send_Email_Lbl, errorMsg)); } return(emailWasSent); }
/// <summary> /// Persist the specified application error to the data store. Return the ID of the error. /// </summary> /// <param name="appError">The application error to persist to the data store.</param> /// <returns> /// Return the ID of the error. If this is a new error object and a new ID has been /// assigned, then this value has also been assigned to the ID property of the object. /// </returns> public override int AppError_Save(IAppError appError) { return(Error.Save(appError)); }
/// <summary> /// Sends an e-mail containing details about the <paramref name="appError" /> to all users who are configured to receive error /// notifications in the gallery identified by <see cref="IAppError.GalleryId" />. If the error is not associated with a particular /// gallery (that is, <see cref="IAppError.GalleryId" /> == <see cref="Int32.MinValue" />, then e-mails are sent to users in all /// galleries who are configured to receive e-mailed error reports. The property <see cref="IGallerySettings.UsersToNotifyWhenErrorOccurs" /> /// defines this list of users. /// </summary> /// <param name="appError">The application error to be sent to users.</param> /// <param name="gallerySettingsCollection">The settings for all galleries. If the <paramref name="appError" /> is associated with /// a particular gallery, then only the settings for that gallery are used by this function; otherwise users in all galleries are /// notified.</param> /// <exception cref="ArgumentNullException">Thrown when <paramref name="appError" /> or <paramref name="gallerySettingsCollection" /> /// is null.</exception> private static void SendEmail(IAppError appError, IGallerySettingsCollection gallerySettingsCollection) { #region Validation if (appError == null) throw new ArgumentNullException("appError"); if (gallerySettingsCollection == null) throw new ArgumentNullException("gallerySettingsCollection"); // HACK: We don't want to send en email for INFO events. Until this logging API can be properly refactored to handle non-error // types, we just check the message here and skip the email if necessary. if (appError.Message.StartsWith("INFO (not an error):", StringComparison.OrdinalIgnoreCase)) { return; } #endregion if (appError.GalleryId > int.MinValue) { // Use settings from the gallery associated with the error. IGallerySettings gallerySettings = gallerySettingsCollection.FindByGalleryId(appError.GalleryId); if (gallerySettings != null) { SendMail(appError, gallerySettingsCollection.FindByGalleryId(appError.GalleryId), null); } } else { // This is an application-wide error, so loop through every gallery and notify all users, making sure we don't notify anyone more than once. List<String> notifiedUsers = new List<string>(); foreach (IGallerySettings gallerySettings in gallerySettingsCollection) { notifiedUsers.AddRange(SendMail(appError, gallerySettings, notifiedUsers)); } } }
/// <summary> /// Persist the specified application error to the data store. Return the ID of the error. /// </summary> /// <param name="appError">The application error to persist to the data store.</param> /// <returns> /// Return the ID of the error. If this is a new error object and a new ID has been /// assigned, then this value has also been assigned to the ID property of the object. /// </returns> public override int AppError_Save(IAppError appError) { SQLiteCommand cmd = null; try { if (appError.AppErrorId == int.MinValue) { cmd = GetCommandAppErrorInsert(appError); if (cmd.Connection.State == ConnectionState.Closed) cmd.Connection.Open(); appError.AppErrorId = Convert.ToInt32(cmd.ExecuteScalar()); } else { throw new DataException("Cannot update an existing AppError object. Only new objects can be persisted to the data store."); } } finally { if ((!IsTransactionInProgress()) && (cmd != null) && (cmd.Connection != null) && (cmd.Connection.State == ConnectionState.Open)) cmd.Connection.Dispose(); if (cmd != null) cmd.Dispose(); } return appError.AppErrorId; }
/// <summary> /// Sends an e-mail containing details about the <paramref name="appError" /> to the specified <paramref name="user" />. Returns /// <c>true</c> if the e-mail is successfully sent. /// </summary> /// <param name="appError">The application error to be sent to users.</param> /// <param name="user">The user to send the e-mail to.</param> /// <param name="gallerySettings">The gallery settings containing the e-mail configuration data.</param> /// <param name="emailSender">The account that that will appear in the "From" portion of the e-mail.</param> /// <returns>Returns <c>true</c> if the e-mail is successfully sent; otherwise <c>false</c>.</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="appError" />, <paramref name="user" />, /// <paramref name="gallerySettings" />, or <paramref name="emailSender" /> is null.</exception> private static bool SendMail(IAppError appError, IUserAccount user, IGallerySettings gallerySettings, MailAddress emailSender) { #region Validation if (appError == null) throw new ArgumentNullException("appError"); if (user == null) throw new ArgumentNullException("user"); if (gallerySettings == null) throw new ArgumentNullException("gallerySettings"); if (emailSender == null) throw new ArgumentNullException("emailSender"); #endregion bool emailWasSent = false; if (!IsValidEmail(user.Email)) { return false; } MailAddress emailRecipient = new MailAddress(user.Email, user.UserName); try { using (MailMessage mail = new MailMessage(emailSender, emailRecipient)) { if (String.IsNullOrEmpty(appError.ExceptionType)) mail.Subject = Resources.Email_Subject_When_No_Ex_Type_Present; else mail.Subject = String.Concat(Resources.Email_Subject_Prefix_When_Ex_Type_Present, " ", appError.ExceptionType); mail.Body = appError.ToHtmlPage(); mail.IsBodyHtml = true; using (SmtpClient smtpClient = new SmtpClient()) { smtpClient.EnableSsl = gallerySettings.SendEmailUsingSsl; // Specify SMTP server if it is specified. The server might have been assigned via web.config, // so only update this if we have a config setting. if (!String.IsNullOrEmpty(gallerySettings.SmtpServer)) { smtpClient.Host = gallerySettings.SmtpServer; } // Specify port number if it is specified and it's not the default value of 25. The port // might have been assigned via web.config, so only update this if we have a config setting. int smtpServerPort; if (!Int32.TryParse(gallerySettings.SmtpServerPort, out smtpServerPort)) smtpServerPort = int.MinValue; if ((smtpServerPort > 0) && (smtpServerPort != 25)) { smtpClient.Port = smtpServerPort; } smtpClient.Send(mail); } emailWasSent = true; } } catch (Exception ex2) { string errorMsg = String.Concat(ex2.GetType(), ": ", ex2.Message); if (ex2.InnerException != null) errorMsg += String.Concat(" ", ex2.InnerException.GetType(), ": ", ex2.InnerException.Message); appError.ExceptionData.Add(new KeyValuePair<string, string>(Resources.Cannot_Send_Email_Lbl, errorMsg)); } return emailWasSent; }
private static SQLiteCommand GetCommandAppErrorInsert(IAppError appError) { const string sql = @" INSERT INTO [gs_AppError] (FKGalleryId, TimeStamp, ExceptionType, Message, Source, TargetSite, StackTrace, ExceptionData, InnerExType, InnerExMessage, InnerExSource, InnerExTargetSite, InnerExStackTrace, InnerExData, Url, FormVariables, Cookies, SessionVariables, ServerVariables) VALUES (@GalleryId, @TimeStamp, @ExceptionType, @Message, @Source, @TargetSite, @StackTrace, @ExceptionData, @InnerExType, @InnerExMessage, @InnerExSource, @InnerExTargetSite, @InnerExStackTrace, @InnerExData, @Url, @FormVariables, @Cookies, @SessionVariables, @ServerVariables);SELECT last_insert_rowid();"; SQLiteCommand cmd = new SQLiteCommand(sql, GetDBConnectionForGallery()); cmd.Parameters.AddWithValue("@GalleryId", appError.GalleryId); if (appError.TimeStamp > DateTime.MinValue) cmd.Parameters.AddWithValue("@TimeStamp", appError.TimeStamp); else cmd.Parameters.AddWithValue("@TimeStamp", DBNull.Value); cmd.Parameters.AddWithValue("@ExceptionType", appError.ExceptionType); cmd.Parameters.AddWithValue("@Message", appError.Message); cmd.Parameters.AddWithValue("@Source", appError.Source); cmd.Parameters.AddWithValue("@TargetSite", appError.TargetSite); cmd.Parameters.AddWithValue("@StackTrace", appError.StackTrace); cmd.Parameters.AddWithValue("@ExceptionData", ErrorHandler.Error.Serialize(appError.ExceptionData)); cmd.Parameters.AddWithValue("@InnerExType", appError.InnerExType); cmd.Parameters.AddWithValue("@InnerExMessage", appError.InnerExMessage); cmd.Parameters.AddWithValue("@InnerExSource", appError.InnerExSource); cmd.Parameters.AddWithValue("@InnerExTargetSite", appError.InnerExTargetSite); cmd.Parameters.AddWithValue("@InnerExStackTrace", appError.InnerExStackTrace); cmd.Parameters.AddWithValue("@InnerExData", ErrorHandler.Error.Serialize(appError.InnerExData)); cmd.Parameters.AddWithValue("@Url", appError.Url); cmd.Parameters.AddWithValue("@FormVariables", ErrorHandler.Error.Serialize(appError.FormVariables)); cmd.Parameters.AddWithValue("@Cookies", ErrorHandler.Error.Serialize(appError.Cookies)); cmd.Parameters.AddWithValue("@SessionVariables", ErrorHandler.Error.Serialize(appError.SessionVariables)); cmd.Parameters.AddWithValue("@ServerVariables", ErrorHandler.Error.Serialize(appError.ServerVariables)); return cmd; }
/// <summary> /// Persist the specified application error to the data store. Return the ID of the error. /// </summary> /// <param name="appError">The application error to persist to the data store.</param> /// <returns> /// Return the ID of the error. If this is a new error object and a new ID has been /// assigned, then this value has also been assigned to the ID property of the object. /// </returns> public abstract int AppError_Save(IAppError appError);
/// <summary> /// Persist the specified application error to the data store. Return the ID of the error. /// </summary> /// <param name="appError">The application error to persist to the data store.</param> /// <returns> /// Return the ID of the error. If this is a new error object and a new ID has been /// assigned, then this value has also been assigned to the ID property of the object. /// </returns> public override int AppError_Save(IAppError appError) { return Error.Save(appError); }
private static SqlCommand GetCommandErrorInsert(IAppError appError, SqlConnection cn) { //INSERT [gs_AppError] // (FKGalleryId, TimeStamp, ExceptionType, Message, Source, TargetSite, StackTrace, ExceptionData, InnerExType, // InnerExMessage, InnerExSource, InnerExTargetSite, InnerExStackTrace, InnerExData, Url, // FormVariables, Cookies, SessionVariables, ServerVariables) //VALUES (@GalleryId, @TimeStamp, @ExceptionType, @Message, @Source, @TargetSite, @StackTrace, @ExceptionData, @InnerExType, // @InnerExMessage, @InnerExSource, @InnerExTargetSite, @InnerExStackTrace, @InnerExData, @Url, // @FormVariables, @Cookies, @SessionVariables, @ServerVariables) SqlCommand cmd = new SqlCommand(Util.GetSqlName("gs_AppErrorInsert"), cn); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@GalleryId", SqlDbType.Int).Value = appError.GalleryId; cmd.Parameters.Add("@TimeStamp", SqlDbType.DateTime).Value = appError.Timestamp; cmd.Parameters.Add("@ExceptionType", SqlDbType.NVarChar, DataConstants.ErrorExTypeLength).Value = appError.ExceptionType; cmd.Parameters.Add("@Message", SqlDbType.NVarChar, DataConstants.ErrorExMsgLength).Value = appError.Message; cmd.Parameters.Add("@Source", SqlDbType.NVarChar, DataConstants.ErrorExSourceLength).Value = appError.Source; cmd.Parameters.Add("@TargetSite", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = appError.TargetSite; cmd.Parameters.Add("@StackTrace", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = appError.StackTrace; cmd.Parameters.Add("@ExceptionData", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.ExceptionData); cmd.Parameters.Add("@InnerExType", SqlDbType.NVarChar, DataConstants.ErrorExTypeLength).Value = appError.InnerExType; cmd.Parameters.Add("@InnerExMessage", SqlDbType.NVarChar, DataConstants.ErrorExMsgLength).Value = appError.InnerExMessage; cmd.Parameters.Add("@InnerExSource", SqlDbType.NVarChar, DataConstants.ErrorExSourceLength).Value = appError.InnerExSource; cmd.Parameters.Add("@InnerExTargetSite", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = appError.InnerExTargetSite; cmd.Parameters.Add("@InnerExStackTrace", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = appError.InnerExStackTrace; cmd.Parameters.Add("@InnerExData", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.InnerExData); cmd.Parameters.Add("@Url", SqlDbType.NVarChar, DataConstants.ErrorUrlLength).Value = appError.Url; cmd.Parameters.Add("@FormVariables", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.FormVariables); cmd.Parameters.Add("@Cookies", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.Cookies); cmd.Parameters.Add("@SessionVariables", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.SessionVariables); cmd.Parameters.Add("@ServerVariables", SqlDbType.NVarChar, DataConstants.NVarCharMaxLength).Value = ErrorHandler.Error.Serialize(appError.ServerVariables); SqlParameter prm = new SqlParameter("@Identity", SqlDbType.Int, 0, "AppErrorId"); prm.Direction = ParameterDirection.Output; cmd.Parameters.Add(prm); return cmd; }