SqlDependency在MVVM中异常:已调用Start仍报错求助
解决SqlDependency的启动异常问题
你虽然调用了SqlDependency.Start(),但时机和使用方式上有几个关键问题,导致异常依然出现,我来帮你拆解一下:
1. SqlDependency.Start()的调用时机错误
你当前的代码是先打开数据库连接,再调用Start(),但SqlDependency.Start()需要在任何数据库连接打开之前执行。因为这个方法要初始化SQL Server的Service Broker监听机制,包括创建内部消息队列和关联会话。如果连接已经打开,Start的初始化无法关联到这个已打开的连接上,自然会触发"未调用Start()"的异常。
2. 不要重复调用Start()
SqlDependency.Start()是应用级别的初始化操作,只需要调用一次(比如在WPF应用的启动事件里,或者ASP.NET的Global.asax中),而不是每次执行数据库操作都调用。多次调用虽然不会直接报错,但会浪费资源,还可能导致监听状态混乱。
3. 检查SQL命令的格式要求
SqlDependency对SQL语句有严格限制,你的SELECT count(*) from users需要调整一点:
- 必须指定表的架构名(比如
dbo.users,如果你的表在其他架构下就换成对应的),避免SQL Server无法识别监听的目标表。
4. 确保连接字符串一致
调用SqlDependency.Start()时用的连接字符串,必须和你打开数据库连接时用的完全一致,否则监听机制无法关联到对应的连接会话。
修正后的代码示例
首先,在应用启动时调用一次Start()(以WPF的App.xaml.cs为例):
protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); // 仅在应用启动时调用一次 string connStr = ConfigurationManager.ConnectionStrings["StringConnexion"].ConnectionString; SqlDependency.Start(connStr); } protected override void OnExit(ExitEventArgs e) { base.OnExit(e); // 应用退出时停止监听,释放资源 string connStr = ConfigurationManager.ConnectionStrings["StringConnexion"].ConnectionString; SqlDependency.Stop(connStr); }
然后修改你的业务方法:
public void something() { string connStr = ConfigurationManager.ConnectionStrings["StringConnexion"].ConnectionString; using (SqlConnection connection = new SqlConnection(connStr)) { connection.Open(); using (SqlCommand command = new SqlCommand("SELECT count(*) FROM dbo.users", connection)) { // 重置命令的通知属性,确保订阅能正常生效 command.Notification = null; SqlDependency dependency = new SqlDependency(command); dependency.OnChange += OnDependencyChange; using (SqlDataReader reader = command.ExecuteReader()) { if (reader.Read()) { var userCount = reader.GetInt32(0); MessageBox.Show(userCount.ToString()); UserCount = userCount.ToString(); } } } } } private void OnDependencyChange(object sender, SqlNotificationEventArgs e) { // 处理数据变更逻辑,注意要重新订阅下一次监听 SqlDependency dependency = sender as SqlDependency; dependency.OnChange -= OnDependencyChange; // 重新执行查询并订阅,保证持续监听 something(); }
另外还要确保你的SQL Server已经启用了Service Broker,可以用这个SQL命令检查:
SELECT name, is_broker_enabled FROM sys.databases WHERE name = '你的数据库名';
如果is_broker_enabled的值是0,执行下面的命令启用:
ALTER DATABASE 你的数据库名 SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE;
内容的提问来源于stack exchange,提问作者Black Panther
相关产品推荐
相关产品推荐

