public void ExecuteSQLonTarget(TargetServerInfo targetServer, AsyncUpdateStatus updateStatus, AsyncQueueBCPJob queueBCPJob, string sqlToExecute) { DateTime dtStart = DateTime.Now; AsyncNotificationEventArgs eventArgs = new AsyncNotificationEventArgs(NotificationEventFunctionCode.ExecuteSqlOnAzure, 0, "", CommonFunc.FormatString(Properties.Resources.ProcessStarted, dtStart.ToString(), dtStart.ToUniversalTime().ToString()) + Environment.NewLine, Color.DarkSlateBlue); StringCollection strColl = new StringCollection(); StringCollection bcpUploadCommands = new StringCollection(); bool inBCPCommand = false; int idx = 0; AsyncProcessingStatus.FinishedProcessingJobs = true; updateStatus(eventArgs); string connectionStr = targetServer.ConnectionStringTargetDatabase; CommentAreaHelper cah = new CommentAreaHelper(); try { cah.FindCommentAreas(sqlToExecute); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } long lCharCnt = 0; int sqlCmdLoopCtr = 0; AsyncProcessingStatus.NumberOfCommands = 0; AsyncProcessingStatus.NumberOfCommandsExecuted = 0; if (cah.Lines.Count() > 0) { foreach (string line in cah.Lines) { if (line.Trim().Equals(Properties.Resources.Go) && !cah.IsIndexInComments(lCharCnt)) { AsyncProcessingStatus.NumberOfCommands++; } lCharCnt += line.Length + cah.CrLf; } } using (SqlConnection con = new SqlConnection(connectionStr)) { StringBuilder sql = new StringBuilder(5000); StringCollection sqlDepends = new StringCollection(); string currentObject = ""; bool comment = false; try { Retry.ExecuteRetryAction(() => { con.Open(); }, () => { con.Close(); }); } catch (Exception ex) { eventArgs.DisplayColor = Color.Red; eventArgs.PercentComplete = 100; if (ex is SqlException) { eventArgs.DisplayText = CommonFunc.FormatString(Properties.Resources.ProcessAborting, ((SqlException)ex).Number.ToString(), ex.Message, sql.ToString(), DateTime.Now.ToString(CultureInfo.CurrentCulture)) + Environment.NewLine; } else { eventArgs.DisplayText = CommonFunc.FormatString(Properties.Resources.ProcessAborting, "", ex.Message, sql.ToString(), DateTime.Now.ToString(CultureInfo.CurrentCulture)) + Environment.NewLine; } updateStatus(eventArgs); return; } lCharCnt = 0; foreach (string sqlCmd in cah.Lines) { ++sqlCmdLoopCtr; if (CancelProcessing) { con.Close(); eventArgs.StatusMsg = Properties.Resources.Canceled; eventArgs.DisplayColor = Color.DarkCyan; eventArgs.DisplayText = Environment.NewLine + CommonFunc.FormatString(Properties.Resources.ProcessCanceledAt, DateTime.Now.ToString(CultureInfo.CurrentCulture)) + Environment.NewLine; eventArgs.PercentComplete = 100; updateStatus(eventArgs); return; } if (inBCPCommand) { if (sqlCmd.Length == 0) { ++lCharCnt; continue; // Get rid of blank line when in BCP Command } if (sqlCmd.Trim().Equals(Properties.Resources.Go) && !cah.IsIndexInComments(lCharCnt)) { sql.Remove(0, sql.Length); inBCPCommand = false; lCharCnt += sqlCmd.Length + cah.CrLf; continue; } } if (sqlCmd.StartsWith(CommonFunc.FormatString(Properties.Resources.RemoveComment))) { lCharCnt += sqlCmd.Length + cah.CrLf; continue; // Get rid of program generated comments } if (!comment) { idx = sqlCmd.IndexOf(CommonFunc.FormatString(Properties.Resources.RemoveCommentStart)); if (idx > -1) { comment = true; lCharCnt += sqlCmd.Length + cah.CrLf; continue; } } else { idx = sqlCmd.IndexOf(CommonFunc.FormatString(Properties.Resources.RemoveCommentEnd)); if (idx > -1) { comment = false; lCharCnt += sqlCmd.Length + cah.CrLf; continue; } lCharCnt += sqlCmd.Length + cah.CrLf; continue; } // Look for BCP string. I.E. "-- BCPArgs:2345:.dbo.Categories" in "C:\Users\ghuey\AppData\Local\Temp\tmp1CD8.tmp" -n -E if (sqlCmd.StartsWith("-- BCPArgs:", StringComparison.Ordinal)) { BCPUploadData(targetServer, updateStatus, queueBCPJob, sqlCmd.Substring(11), ref bcpUploadCommands); // if queueBCPJob is null, then BCP upload is not queued up for a parallel batch process (basically, it is finished by now). if (queueBCPJob == null) { ++AsyncProcessingStatus.NumberOfCommandsExecuted; eventArgs.DisplayText = ""; eventArgs.PercentComplete = (int)(((float)AsyncProcessingStatus.NumberOfCommandsExecuted / (float)AsyncProcessingStatus.NumberOfCommands) * 100.0); eventArgs.StatusMsg = CommonFunc.FormatString(Properties.Resources.BCPProcessingStatus, AsyncProcessingStatus.NumberOfCommandsExecuted.ToString(), AsyncProcessingStatus.NumberOfCommands.ToString()); updateStatus(eventArgs); } inBCPCommand = true; lCharCnt += sqlCmd.Length + cah.CrLf; continue; } if (sqlCmd.Trim().Equals(Properties.Resources.Go) && !cah.IsIndexInComments(lCharCnt) || sqlCmdLoopCtr == cah.Lines.Count()) { if (sql.Length == 0) { lCharCnt += sqlCmd.Length + cah.CrLf; continue; } try { Retry.ExecuteRetryAction(() => { NonQueryResults nqr = SqlHelper.ExecuteNonQuery(con, CommandType.Text, sql.ToString()); }, () => { ResetConnection(con); }); Match cmdStr = Regex.Match(sql.ToString(), "(CREATE|ALTER)[\\w\\W]+(INDEX|TABLE|VIEW|PROCEDURE|ROLE|SCHEMA|TRIGGER|TYPE).*", RegexOptions.IgnoreCase); if (cmdStr.Success) { int cr = cmdStr.Value.IndexOf("\r"); if (cr > 0) { currentObject = cmdStr.Value.Substring(0, cr > 70 ? 70 : cr); } else { currentObject = cmdStr.Value.Substring(0, cmdStr.Value.Length > 70 ? 70 : cmdStr.Value.Length); } } else { currentObject = sql.ToString().Substring(0, sql.ToString().Length > 70 ? 70 : sql.ToString().Length); } currentObject = currentObject.Replace("\r", "").Replace("\n", " "); eventArgs.DisplayColor = Color.DarkGreen; eventArgs.DisplayText = Properties.Resources.Success + " " + currentObject + Environment.NewLine; } catch (Exception ex) { eventArgs.DisplayColor = Color.Red; if (ex is SqlException) { if (((SqlException)ex).Number == 208) { --AsyncProcessingStatus.NumberOfCommandsExecuted; sqlDepends.Add(sql.ToString()); eventArgs.DisplayText = ""; } else { eventArgs.DisplayText = DateTime.Now.ToString(CultureInfo.CurrentCulture) + CommonFunc.FormatString(Properties.Resources.ErrorNumAndMsg, ((SqlException)ex).Number.ToString(), ex.Message) + Environment.NewLine + sql.ToString() + Environment.NewLine; } } else { eventArgs.DisplayText = DateTime.Now.ToString(CultureInfo.CurrentCulture) + CommonFunc.FormatString(Properties.Resources.ErrorNumAndMsg, "", ex.Message) + Environment.NewLine + sql.ToString() + Environment.NewLine; } } ++AsyncProcessingStatus.NumberOfCommandsExecuted; eventArgs.PercentComplete = (int)(((float)AsyncProcessingStatus.NumberOfCommandsExecuted / (float)AsyncProcessingStatus.NumberOfCommands) * 100.0); eventArgs.StatusMsg = CommonFunc.FormatString(Properties.Resources.BCPProcessingStatus, AsyncProcessingStatus.NumberOfCommandsExecuted.ToString(), AsyncProcessingStatus.NumberOfCommands.ToString()); updateStatus(eventArgs); sql.Remove(0, sql.Length); } else { sql.AppendLine(sqlCmd); } lCharCnt += sqlCmd.Length + cah.CrLf; } // Ok, check for error that happened because of dependency and retry foreach (string sqlDep in sqlDepends) { try { Retry.ExecuteRetryAction(() => { NonQueryResults nqr = SqlHelper.ExecuteNonQuery(con, CommandType.Text, sqlDep); }, () => { ResetConnection(con); }); int startIdx = sqlDep.IndexOf("CREATE ", 0, StringComparison.CurrentCultureIgnoreCase); if (startIdx < 0) { startIdx = sqlDep.IndexOf("ALTER ", 0, StringComparison.CurrentCultureIgnoreCase); } int len = sqlDep.Substring(startIdx).Length > 70 ? 70 : sqlDep.Substring(startIdx).Length; currentObject = sqlDep.Substring(startIdx, len) + " ..."; eventArgs.DisplayColor = Color.DarkGreen; eventArgs.DisplayText = Properties.Resources.Success + " " + currentObject.Replace("\r", "").Replace("\n", " ") + Environment.NewLine; } catch (Exception ex) { eventArgs.DisplayColor = Color.Red; if (ex is SqlException) { eventArgs.DisplayText = DateTime.Now.ToString(CultureInfo.CurrentCulture) + CommonFunc.FormatString(Properties.Resources.ErrorNumAndMsg, ((SqlException)ex).Number.ToString(), ex.Message) + Environment.NewLine + sql.ToString() + Environment.NewLine; } else { eventArgs.DisplayText = DateTime.Now.ToString(CultureInfo.CurrentCulture) + CommonFunc.FormatString(Properties.Resources.ErrorNumAndMsg, "", ex.Message) + Environment.NewLine + sql.ToString() + Environment.NewLine; } } ++AsyncProcessingStatus.NumberOfCommandsExecuted; eventArgs.PercentComplete = (int)(((float)AsyncProcessingStatus.NumberOfCommandsExecuted / (float)AsyncProcessingStatus.NumberOfCommands) * 100.0); eventArgs.StatusMsg = CommonFunc.FormatString(Properties.Resources.BCPProcessingStatus, AsyncProcessingStatus.NumberOfCommandsExecuted.ToString(), AsyncProcessingStatus.NumberOfCommands.ToString()); updateStatus(eventArgs); } con.Close(); // Output BCP upload command summary if (bcpUploadCommands.Count > 0) { eventArgs.DisplayColor = Color.Green; eventArgs.DisplayText = Properties.Resources.BCPUploadSummary + Environment.NewLine; eventArgs.PercentComplete = 99; updateStatus(eventArgs); foreach (string bcpUploadCommand in bcpUploadCommands) { eventArgs.DisplayText = bcpUploadCommand + Environment.NewLine; updateStatus(eventArgs); } } AsyncProcessingStatus.FinishedAddingJobs = true; while (true) { if (AsyncProcessingStatus.FinishedProcessingJobs) { break; } Thread.Sleep(500); } // Done DateTime dtEnd = DateTime.Now; TimeSpan tsDuration = dtEnd.Subtract(dtStart); string sHour = tsDuration.Hours == 1 ? Properties.Resources.TimeHour : Properties.Resources.TimeHours; string sMin = tsDuration.Minutes == 1 ? Properties.Resources.TimeMinute : Properties.Resources.TimeMinutes; string sSecs = tsDuration.Seconds == 1 ? Properties.Resources.TimeSecond : Properties.Resources.TimeSeconds; eventArgs.StatusMsg = Properties.Resources.Done; eventArgs.DisplayColor = Color.DarkCyan; eventArgs.DisplayText = CommonFunc.FormatString(Properties.Resources.ProcessingFinished, dtEnd.ToString(), dtEnd.ToUniversalTime().ToString(), tsDuration.Hours + sHour + tsDuration.Minutes.ToString() + sMin + tsDuration.Seconds.ToString() + sSecs); eventArgs.PercentComplete = 100; updateStatus(eventArgs); } }
public bool ParseFile(SMOScriptOptions options, bool _ParseFile, AsyncNotificationEventArgs e) { DateTime startTime = DateTime.Now; ScriptDatabase sdb = new ScriptDatabase(); if (e.FunctionCode == NotificationEventFunctionCode.ParseFolder) { FileInfo fi = new FileInfo(_FileToProcess); _SwTsql = new StreamWriter(_TargetFile, false); sdb.Initialize(_Output.StatusUpdateHandler, options, false, _FileToProcess, _SwTsql); } else { sdb.Initialize(_Output.StatusUpdateHandler, options, false); } /****************************************************************/ string sqlText = CommonFunc.GetTextFromFile(_FileToProcess); CommentAreaHelper cah = new CommentAreaHelper(); long totalCharacterOffset = 0; bool bCommentedLine = false; List <string> sqlCmds = new List <string>(); if (_ParseFile) { StringBuilder sb = new StringBuilder(); cah.FindCommentAreas(sqlText); foreach (string line in cah.Lines) { if (line.Equals(Properties.Resources.Go, StringComparison.OrdinalIgnoreCase)) { if (!cah.IsIndexInComments(totalCharacterOffset)) { sqlCmds.Add(sb.ToString()); sb.Length = 0; } else { sb.Append(line + Environment.NewLine); } } else { sb.Append(line + Environment.NewLine); } totalCharacterOffset += line.Length + cah.CrLf; } if (sb.Length > 0) { sqlCmds.Add(sb.ToString()); sb.Length = 0; } } else { sqlCmds.Add(sqlText); } int numCmds = sqlCmds.Count(); int loopCtr = 0; if (numCmds == 0) { e.DisplayText = CommonFunc.FormatString(Properties.Resources.MessageNoDataToProcess + Environment.NewLine, _FileToProcess); if (e.FunctionCode == NotificationEventFunctionCode.ParseFile) { e.PercentComplete = 100; } else if (e.FunctionCode == NotificationEventFunctionCode.ParseFolder) { e.FilesProcessed++; } _Output.StatusUpdateHandler(e); return(false); } e.DisplayColor = Color.DarkBlue; e.DisplayText = ""; if (e.FunctionCode == NotificationEventFunctionCode.ParseFile) { e.StatusMsg = CommonFunc.FormatString(Properties.Resources.MessageProcessingStatus, loopCtr.ToString(), numCmds.ToString()); e.PercentComplete = 0; } else if (e.FunctionCode == NotificationEventFunctionCode.ParseFolder) { e.TotalDenominator = e.TotalDenominator + numCmds; } _Output.StatusUpdateHandler(e); totalCharacterOffset = 0; foreach (string cmd in sqlCmds) { ++loopCtr; if (AsyncProcessingStatus.CancelProcessing) { break; } if (cmd.Length == 0 || cmd.Equals(Environment.NewLine)) { continue; } foreach (CommentArea ca in cah.CommentAreas) { if (ca.Start == totalCharacterOffset && ca.End == totalCharacterOffset + cmd.Length - cah.CrLf - 1) // note that the -1 is to put you at zero based counting { bCommentedLine = true; break; } bCommentedLine = false; } totalCharacterOffset += cmd.Length + cah.CrLf; if (_ParseFile && !bCommentedLine && !(cmd.StartsWith("/*~") || cmd.StartsWith("~*/"))) { if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sPROCEDURE", RegexOptions.IgnoreCase)) { sdb.ParseFileTSQLGo(cmd); } else if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sTABLE", RegexOptions.IgnoreCase)) { sdb.ParseFileTable(cmd); } else if (Regex.IsMatch(cmd, "CREATE\\sXML\\sSCHEMA\\sCOLLECTION", RegexOptions.IgnoreCase)) { sdb.ParseFileXMLSchemaCollections(cmd); } else if (Regex.IsMatch(cmd, "CREATE\\sTYPE", RegexOptions.IgnoreCase)) { sdb.ParseFileUDT(cmd); } else if (Regex.IsMatch(cmd, "CREATE\\s[a-z\\s]*\\sINDEX", RegexOptions.IgnoreCase)) { sdb.ParseFileIndex(cmd); } else if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sROLE", RegexOptions.IgnoreCase)) { sdb.ParseFileRole(cmd); } else if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sSYNONYM", RegexOptions.IgnoreCase)) { sdb.ParseFileSynonyms(cmd); } else if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sSCHEMA", RegexOptions.IgnoreCase)) { sdb.ParseFileSchemas(cmd); } else if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sASSEMBLY", RegexOptions.IgnoreCase)) { sdb.ParseFileAssemblies(cmd); } else if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sPARTITIONFUNCTIONS", RegexOptions.IgnoreCase)) { sdb.ParseFilePartitionFunctions(cmd); } else if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sPARTITIONSCHEMES", RegexOptions.IgnoreCase)) { sdb.ParseFilePartitionSchemes(cmd); } else { sdb.ParseFileTSQLGo(cmd); } if (e.FunctionCode == NotificationEventFunctionCode.ParseFolder) { e.NumeratorComplete = e.NumeratorComplete + 1; } } else { sdb.OutputSQLString(cmd, Color.Black); } if (loopCtr % 20 == 0) { e.DisplayColor = Color.DarkBlue; e.DisplayText = ""; if (e.FunctionCode == NotificationEventFunctionCode.ParseFile) { e.PercentComplete = (int)(((float)loopCtr / (float)numCmds) * 100.0); e.StatusMsg = CommonFunc.FormatString(Properties.Resources.MessageProcessingStatus, loopCtr.ToString(), numCmds.ToString()); } else if (e.FunctionCode == NotificationEventFunctionCode.ParseFolder) { e.PercentComplete = (int)(((float)e.NumeratorComplete / (float)e.TotalDenominator) * 100); } _Output.StatusUpdateHandler(e); } } DateTime endTime = DateTime.Now; if (e.FunctionCode == NotificationEventFunctionCode.ParseFile) { if (AsyncProcessingStatus.CancelProcessing) { e.DisplayText = CommonFunc.FormatString(Properties.Resources.MessageCanceledProcessing, DateTime.Now.ToString()) + Environment.NewLine; e.StatusMsg = Properties.Resources.MessageCanceled; } else { e.DisplayColor = Color.DarkCyan; if (_ParseFile) { e.DisplayText = Properties.Resources.AnalysisComplete + Environment.NewLine; } else { e.DisplayText = Properties.Resources.MessageFileReadAndReady; } e.StatusMsg = Properties.Resources.Done; } e.PercentComplete = 100; e.DisplayText = CommonFunc.FormatString(Properties.Resources.MessageTotalFileProcessingTime + Environment.NewLine, endTime.Subtract(startTime).ToString(), Properties.Resources.RemoveComment, _FileToProcess.ToString()); _Output.StatusUpdateHandler(e); } else if (e.FunctionCode == NotificationEventFunctionCode.ParseFolder) { _SwTsql.Flush(); _SwTsql.Close(); if (sdb.IssuesFound == true) { e.DisplayText = Properties.Resources.MessageFileChangedState + CommonFunc.FormatString(Properties.Resources.MessageTotalFileProcessingTime, endTime.Subtract(startTime).ToString(), _FileToProcess.ToString()) + Environment.NewLine; e.DisplayColor = Color.Brown; } else { e.DisplayText = Properties.Resources.MessageFileNoChangeState + CommonFunc.FormatString(Properties.Resources.MessageTotalFileProcessingTime, endTime.Subtract(startTime).ToString(), _FileToProcess.ToString()) + Environment.NewLine; e.DisplayColor = Color.DarkBlue; } _Output.StatusUpdateHandler(e); e.FilesProcessed++; } return(sdb.IssuesFound); }
public void ParseFile(string _FileToProcess, bool _ParseFile) { DateTime startTime = DateTime.Now; AsyncNotificationEventArgs e = new AsyncNotificationEventArgs(NotificationEventFunctionCode.ParseFile, 0, "", "", Color.Black); ScriptDatabase sdb = new ScriptDatabase(); sdb.Initialize(_Output.StatusUpdateHandler, SMOScriptOptions.CreateFromConfig(), false); /****************************************************************/ string sqlText = CommonFunc.GetTextFromFile(_FileToProcess); CommentAreaHelper cah = new CommentAreaHelper(); long totalCharacterOffset = 0; bool bCommentedLine = false; List <string> sqlCmds = new List <string>(); if (_ParseFile) { StringBuilder sb = new StringBuilder(); cah.FindCommentAreas(sqlText); foreach (string line in cah.Lines) { if (line.Equals(Properties.Resources.Go, StringComparison.OrdinalIgnoreCase)) { if (!cah.IsIndexInComments(totalCharacterOffset)) { sqlCmds.Add(sb.ToString()); sb.Length = 0; } else { sb.Append(line + Environment.NewLine); } } else { sb.Append(line + Environment.NewLine); } totalCharacterOffset += line.Length + cah.CrLf; } } else { sqlCmds.Add(sqlText); } int numCmds = sqlCmds.Count(); if (numCmds == 0) { e.PercentComplete = 100; e.DisplayText = "No data to process"; _Output.StatusUpdateHandler(e); return; } int loopCtr = 0; e.DisplayColor = Color.DarkBlue; e.DisplayText = ""; e.StatusMsg = "Processing " + loopCtr.ToString() + " out of " + numCmds.ToString(); e.PercentComplete = 0; _Output.StatusUpdateHandler(e); totalCharacterOffset = 0; foreach (string cmd in sqlCmds) { ++loopCtr; if (AsyncProcessingStatus.CancelProcessing) { break; } if (cmd.Length == 0 || cmd.Equals(Environment.NewLine)) { continue; } foreach (CommentArea ca in cah.CommentAreas) { if (ca.Start == totalCharacterOffset && ca.End == totalCharacterOffset + cmd.Length - cah.CrLf - 1) // note that the -1 is to put you at zero based counting { bCommentedLine = true; break; } bCommentedLine = false; } totalCharacterOffset += cmd.Length + cah.CrLf; if (_ParseFile && !bCommentedLine && !(cmd.StartsWith("/*~") || cmd.StartsWith("~*/"))) { if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sPROCEDURE", RegexOptions.IgnoreCase)) { sdb.ParseFileTSQLGo(cmd); } else if (Regex.IsMatch(cmd, "(CREATE|ALTER)\\sTABLE", RegexOptions.IgnoreCase)) { sdb.ParseFileTable(cmd); } else if (Regex.IsMatch(cmd, "CREATE\\sXML\\sSCHEMA\\sCOLLECTION", RegexOptions.IgnoreCase)) { sdb.ParseFileXMLSchemaCollections(cmd); } else if (Regex.IsMatch(cmd, "CREATE\\sTYPE", RegexOptions.IgnoreCase)) { sdb.ParseFileUDT(cmd); } else if (Regex.IsMatch(cmd, "CREATE\\s[a-z\\s]*\\sINDEX", RegexOptions.IgnoreCase)) { sdb.ParseFileIndex(cmd); } else if (Regex.IsMatch(cmd, "CREATE ROLE", RegexOptions.IgnoreCase)) { sdb.ParseFileRole(cmd); } else { sdb.ParseFileTSQLGo(cmd); } } else { sdb.OutputSQLString(cmd, Color.Black); } if (loopCtr % 20 == 0) { e.PercentComplete = (int)(((float)loopCtr / (float)numCmds) * 100.0); e.DisplayColor = Color.DarkBlue; e.DisplayText = ""; e.StatusMsg = "Processing " + loopCtr.ToString() + " out of " + numCmds.ToString(); _Output.StatusUpdateHandler(e); } } if (AsyncProcessingStatus.CancelProcessing) { e.DisplayText = "Canceled processing ..." + Environment.NewLine; e.StatusMsg = "Canceled!"; } else { e.DisplayColor = Color.DarkCyan; if (_ParseFile) { e.DisplayText = Properties.Resources.AnalysisComplete + Environment.NewLine; } else { e.DisplayText = "File read and ready for processing."; } e.StatusMsg = "Done!"; } e.PercentComplete = 100; _Output.StatusUpdateHandler(e); DateTime endTime = DateTime.Now; e.DisplayText = string.Format( "{1}Total processing time --> {0}", endTime.Subtract(startTime).ToString(), Properties.Resources.RemoveComment); _Output.StatusUpdateHandler(e); }