【问题标题】:Serializing Aysnchronous SQLCommand序列化异步 SQLCommand
【发布时间】:2015-01-13 13:50:45
【问题描述】:

下面的代码在 Session 状态为 InProc 时可以正常工作。但是,当 Session 状态为 Sql Server 时,HandleCallback 永远不会被调用。如何更改代码以便调用 HandleCallBack?

    private void TAdata(object sender, EventArgs e)
    {
        if (((Form)sender).DialogResult == DialogResult.No)
        {
            return;
        }

        if (Changed)
        {
            MessageBox.Show(this.ParentForm, "Save Payroll Changes First", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }
        else
        {
            SqlConnection dbconnAS = new SqlConnection(strDBconnAS);
            {
                try
                {
                    AsyncCallback callback = new AsyncCallback(HandleCallback);
                    using (SqlCommand SQLcmd = new SqlCommand("dbo.KronosTaData", dbconnAS))
                    {
                        SQLcmd.CommandType = CommandType.StoredProcedure;
                        dbconnAS.Open();
                        Changed = true;
                        SQLcmd.BeginExecuteNonQuery(callback, SQLcmd);
                        strResult = "";
                        ExportProgress.Visible = true;
                        ExportProgress.Value = 0;
                        ExportProgress.Maximum = 120;
                        ExportTimer.Start();
                    }
                }
                catch (Exception ex)
                {
                    Changed = false;
                    strResult = ex.Message;
                    if (dbconnAS != null)
                    {
                        dbconnAS.Close();
                    }
                }
            }
        }
    }

    private void HandleCallback(IAsyncResult result)
    {
        try
        {
            using (SqlCommand SQLcmd = (SqlCommand)result.AsyncState)
            {
                int rowCount = SQLcmd.EndExecuteNonQuery(result);
                strResult = "OK";
                SQLcmd.Connection.Close();
            }
        }
        catch (Exception ex)
        {
            strResult = ex.Message;
        }

    }

    private void ExportTimer_Tick(object sender, EventArgs e)
    {
        //Timer Exists on UI thread
        if (strResult == "")
        {
            if (cmdKronos.Enabled) cmdKronos.Enabled = false;
            if (ExportProgress.Value > ExportProgress.Maximum - 10) ExportProgress.Maximum += 10;
            ExportProgress.Value += 1;
        }
        else if (strResult == "OK")
        {
            Changed = false;
            cmdKronos.Enabled = true;
            ExportProgress.Visible = false;
            ExportTimer.Stop();
            MessageBox.Show(ParentForm, "Kronos data succesfully imported", "Data Import", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        else
        {
            Changed = false;
            cmdKronos.Enabled = true;
            ExportProgress.Visible = false;
            ExportTimer.Stop();
            MessageBox.Show(ParentForm, Text, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }
    }

【问题讨论】:

    标签: c# visual-web-gui


    【解决方案1】:

    您将在完成启动命令后立即处理它:

    using (SqlCommand SQLcmd = new SqlCommand("dbo.KronosTaData", dbconnAS))
    {
        //...
        SQLcmd.BeginExecuteNonQuery(callback, SQLcmd);
        //...
    }
    

    这将中止一切 - 确实如此:它永远不会完成。基本上; using 不能很好地与 Begin*/End* 配合使用,所以不要那样做。顺便说一句(通过ExecuteNonQueryAsync),您可能会发现使用async/await要容易得多

    您可能还想在某处关闭并处理连接;再说一遍,async/await 会让这件事变得更容易。

    【讨论】:

    • 在非序列化环境中它工作正常。事实上,失败的关键是使用“使用”来处理 SQL 连接。一旦我把它拿走,它就在 InProc 状态下工作正常。
    • 我尝试了 async / await,但是这些命令在 Visual Webgui 环境中无法正常运行
    • 经过仔细检查,我发现了问题,但不太确定如何解决。问题是当回调触发时,它将 strResult 设置为 OK。但是主线程上 strResult 的值仍然是空字符串。好像突然有两个版本的strResult。
    • @user3540780 线程很难;p 你还没有展示主线程是如何访问strResult,所以我不能评论;但是是的:如果您没有正确同步,事情可能会错误地报告。
    • 主线程有一个定时器正在运行,当 strResult 的值发生变化时它就会停止。计时器增加一个进度条,这是使用 WebGUI 实现此目的的唯一方法
    【解决方案2】:

    解决方法是将变量 strResult 声明为静态。

    Visual Webgui Variable Scope

    【讨论】:

    • 我认为我没有太多选择,因为不同的线程创建单独的变量实例,除非变量被声明为静态的。你能推荐一个替代方案吗?
    • is 完全说“不同的线程创建单独的变量实例”是不正确的。 strResult 是一个字段:它的作用域是对象。您可能看到的是 CPU 级缓存,因为您未能正确同步。再说一遍:我需要查看其他线程访问strResult 的位置以详细评论。 static 表示完全不同
    • 猜错了!我以前从未见过这种情况,因为在内存处理中使用时不会发生这种情况。我只看到它在使用状态服务器时发生。在 VWG 中,静态变量对所有用户都是通用的。因此,在此示例中使用静态变量可能是正确的选择,因为我不希望多个用户在任何给定时间点运行它。
    • 如果问题在于您的对象范围,那么这是您需要解决的单独问题;同样,您仍然没有显示您的使用情况。我不熟悉“VWG”,谷歌一无所获。但是,您的代码看起来像 winforms,在这种情况下,“所有用户”听起来……很奇怪。无论哪种方式,创建结果字段static 似乎仍然是解决此问题的完全错误的方法;正确的方法是双重的: 1:确保您知道您正在与哪个对象实例交谈; 2:同步正确。 static 只涉及其中的第一个(而且方式很糟糕)。两者都是必需的。
    • VWG = Visual WebGui (visualwebgui.com) 代码看起来像 winforms,因为 VWG 背后的整个概念是 web 上的窗口。自从您的 cmets 以来,我对此进行了大量研究。 Microsoft 的方法是使用 Invoke 将变量值传递回主 UI 线程。我尝试了这个但没有成功,但调用工作正常,主 UI 仍然没有得到值。我怀疑是序列化导致了这里的问题。
    猜你喜欢
    • 2021-01-08
    • 1970-01-01
    • 2014-11-15
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多