我已经编写了一个很长的存储过程,我从ASP.NET(3.5)页面调用。
存储过程如下所示:
CREATE PROCEDURE csi_CourseEval_Export
@year
@term
@use_case
AS
BEGIN
SET NOCOUNT ON
PRINT 'Building candidate course list'
.... -- do stuff
PRINT ''
RAISERROR('1', '0', 1) WITH NOWAIT -- flush buffer and indicate step 1 reached
PRINT ''
.... -- do more stuff
PRINT ''
RAISERROR('2', '0', 1) WITH NOWAIT -- flush buffer and indicate step 2 reached
PRINT ''
.... -- do more stuff
PRINT ''
RAISERROR('3', '0', 1) WITH NOWAIT -- flush buffer and indicate step 3 reached
PRINT ''
.... -- do more stuff
.... -- do LOTS more stuff, including steps 4 through 8
PRINT ''
RAISERROR('9', '0', 1) WITH NOWAIT -- flush buffer and indicate step 9 reached
PRINT ''
RAISERROR('DONE', '0', 1) WITH NOWAIT -- flush buffer and indicate completion
END
我的C#codebehind具有以下相关的属性和方法:
private SqlConnection db;
private string exportState = "";
private static string jdbConnectionString = "Data Source=...;Initial Catalog=...;Persist Security Info=True;Asynchronous Processing=true;User ID=...;Password=...";
private void ShowData(GridView display, string table)
{
display.DataSource = new SqlDataSource(CoursEval.jdbConnectionString, "SELECT * FROM ##" + table);
display.DataBind();
}
private void SetControls(bool enable)
{
RunExport.Enabled = enable;
if (enable)
RunExport.Text = "Run";
else
RunExport.Text = "Running";
UseCase.Enabled = enable;
Year.Enabled = enable;
Term.Enabled = enable;
}
private void LogSQL(string message)
{
if (message.Length == 1 || message.Equals("DONE"))
{
exportState = message;
}
SQL_Log.Text += "<br />" + message.Replace(" ", " ").Replace("\n", "<br />");
}
protected void RunExport_Click(object sender, EventArgs e)
{
db = new SqlConnection(jdbConnectionString);
db.FireInfoMessageEventOnUserErrors = true;
db.InfoMessage += delegate(object ds, SqlInfoMessageEventArgs de)
{
LogSQL(de.Message);
};
db.Open();
SqlCommand cmd = new SqlCommand("csi_CourseEval_Export", db);
cmd.Parameters.Add("@year", SqlDbType.VarChar).Value = Year.SelectedValue;
cmd.Parameters.Add("@term", SqlDbType.VarChar).Value = Term.SelectedValue;
cmd.Parameters.Add("@use_case", SqlDbType.VarChar).Value = UseCase.SelectedValue;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0;
SetControls(false);
cmd.ExecuteNonQuery();
ShowData(ShowCourses, "Courses");
ShowData(ShowStudents, "Students");
ShowData(ShowFaculty, "Faculty");
ResultsPanel.Visible = true;
db.Close();
SetControls(true);
}
以下System.Web.UI.WebControls.*
表单对象是相关的:
SQL_Log - Label
RunExport - Button
UseCase, Year and Term - DropDownList
ShowCourses, ShowFaculty, ShowStudent - GridView
ResultsPanel - Panel
症状:
无论我做什么,SQL_Log
标签只会在存储过程的最后更新一次,而其他所有内容都会显示。
期望的行为:
SQL_Log
标签应该异步更新,让用户看到存储过程已经走了多远。
我做错了什么?
编辑: 这是一个部分答案:
更新以使用异步SqlCommand(BeginExecuteNonQuery而不是ExecuteNonQuery)让我进入第一个RAISERROR,但是在调用EndExecuteNonQuery之后我不会再收到任何InfoMessage事件,即使存储过程仍在此时运行
RunExport_Click现在看起来像:
protected void RunExport_Click(object sender, EventArgs e)
{
db = new SqlConnection(CoursEval.jdbConnectionString);
db.FireInfoMessageEventOnUserErrors = true;
db.InfoMessage += delegate(object ds, SqlInfoMessageEventArgs de)
{
LogSQL(de.Message);
};
db.Open();
SqlCommand cmd = new SqlCommand("csi_CourseEval_Export", db);
cmd.Parameters.Add("@year", SqlDbType.VarChar).Value = Year.SelectedValue;
cmd.Parameters.Add("@term", SqlDbType.VarChar).Value = Term.SelectedValue;
cmd.Parameters.Add("@use_case", SqlDbType.VarChar).Value = UseCase.SelectedValue;
cmd.CommandType = CommandType.StoredProcedure;
cmd.StatementCompleted += GetExportResults;
cmd.CommandTimeout = 0;
SetControls(false);
cmd.BeginExecuteNonQuery(new AsyncCallback(FinishExport), cmd);
}
我现在有三个额外的功能,ShowResults,GetExportResults和FinishExport:
private void ShowResults()
{
ShowData(ShowCourses, "Courses");
ShowData(ShowFaculty, "Faculty");
ShowData(ShowFacultyEnrollment, "FacultyEnrollment");
ShowData(ShowStudents, "Students");
ShowData(ShowStudentEnrollment, "StudentEnrollment");
ResultsPanel.Visible = true;
}
private void FinishExport(IAsyncResult result)
{
if (result.IsCompleted)
{
SqlCommand cmd = (SqlCommand)result.AsyncState;
cmd.EndExecuteNonQuery(result);
}
else
{
RunExport.Text = exportState;
}
}
private void GetExportResults(object sender, StatementCompletedEventArgs e)
{
ShowResults();
db.Close();
SetControls(true);
}
此外,LogSQL现在看起来像这样:
private void LogSQL(string message)
{
if (message.Length == 1 || message.Equals("DONE"))
{
exportState = message;
}
SQL_Log.Text += "<br />" + message.Replace(" ", " ").Replace("\n", "<br />");
ProgressPanel.Update();
}
其中ProgressPanel是AJAX驱动的UpdatePanel,其中包含所有内容。
脚本现在到达第2阶段RAISERROR,此时FinishExport将触发,我不会再收到任何InfoMessage事件。 GetExportResults永远不会触发,因此整个页面基本上都会挂起。我错过了什么?
答案 0 :(得分:0)
无法异步更新标签 - Web应用程序无法正常工作。当您的页面执行时,它会将HTML发送到浏览器,然后销毁。没有简单的过程可以继续将更新的HTML发送到浏览器。