读取SQL Server代理消息并使用NServiceBus发布它们
我对NServiceBus非常陌生,在我们的一个项目中,我们希望实现以下目标-读取SQL Server代理消息并使用NServiceBus发布它们,nservicebus,Nservicebus,我对NServiceBus非常陌生,在我们的一个项目中,我们希望实现以下目标- 每当在Sql server中修改表数据时,构造一条消息并插入Sql server代理队列 使用NServiceBus读取代理队列消息 将消息作为另一个事件再次发布,以便其他订阅者 我能应付 现在是第二点,我没有太多的线索,如何完成它 我参考了以下文章,之后我可以在代理队列中输入消息,但无法在我们的项目中与NServiceBus集成,因为NServiceBus库的版本较旧,而且使用的许多方法也不推荐。所以在当前版本中使
谢谢。据我记忆所及,ServiceBroker传输非常旧,不再受支持。 一个可能的解决方案是使用类似SqlDependency()的东西从端点代码“监视”感兴趣的表,然后将消息推送到相关队列中
.m我使用的是nServiceBus(5)、VS2013和SQL Server 2008的当前版本。我使用创建了一个数据库更改侦听器,它使用SQLServer对象代理和SQLDependency来监视对特定表的更改。(注意,在SQL Server的更高版本中,这可能会被弃用) SQL依赖关系允许您使用所有基本SQL功能的广泛选择,尽管有一些需要注意的功能。我稍微修改了教程中的代码,以提供更好的错误信息:
void NotifyOnChange(object sender, SqlNotificationEventArgs e)
{
// Check for any errors
if (@"Subscribe|Unknown".Contains(e.Type.ToString())) { throw _DisplayErrorDetails(e); }
var dependency = sender as SqlDependency;
if (dependency != null) dependency.OnChange -= NotifyOnChange;
if (OnChange != null) { OnChange(); }
}
private Exception _DisplayErrorDetails(SqlNotificationEventArgs e)
{
var message = "useful error info";
var messageInner = string.Format("Type:{0}, Source:{1}, Info:{2}", e.Type.ToString(), e.Source.ToString(), e.Info.ToString());
if (@"Subscribe".Contains(e.Type.ToString()) && @"Invalid".Contains(e.Info.ToString()))
messageInner += "\r\n\nThe subscriber says that the statement is invalid - check your SQL statement conforms to specified requirements (http://stackoverflow.com/questions/7588572/what-are-the-limitations-of-sqldependency/7588660#7588660).\n\n";
return new Exception(messageMain, new Exception(messageInner));
}
我还创建了一个具有“数据库优先”实体框架数据模型的项目,以允许我处理更改后的数据
我的nServiceBus项目的[相关部分]包括两个“作为主机运行”端点,其中一个端点发布事件消息。第二个端点处理消息。发布服务器已设置为IWantToRunAtStartup,它实例化DBListener,并将我希望作为更改监视器运行的SQL语句传递给它。onChange()函数通过一个匿名函数读取更改的数据并发布消息:
using statements
namespace Sample4.TestItemRequest
{
public partial class MyExampleSender : IWantToRunWhenBusStartsAndStops
{
private string NOTIFY_SQL = @"SELECT [id] FROM [dbo].[Test] WITH(NOLOCK) WHERE ISNULL([Status], 'N') = 'N'";
public void Start() { _StartListening(); }
public void Stop() { throw new NotImplementedException(); }
private void _StartListening()
{
var db = new Models.TestEntities();
// Instantiate a new DBListener with the specified connection string
var changeListener = new DatabaseChangeListener(ConfigurationManager.ConnectionStrings["TestConnection"].ConnectionString);
// Assign the code within the braces to the DBListener's onChange event
changeListener.OnChange += () =>
{
/* START OF EVENT HANDLING CODE */
//This uses LINQ against the EF data model to get the changed records
IEnumerable<Models.TestItems> _NewTestItems = DataAccessLibrary.GetInitialDataSet(db);
while (_NewTestItems.Count() > 0)
{
foreach (var qq in _NewTestItems)
{
// Do some processing, if required
var newTestItem = new NewTestStarted() { ... set properties from qq object ... };
Bus.Publish(newTestItem);
}
// Because there might be a number of new rows added, I grab them in small batches until finished.
// Probably better to use RX to do this, but this will do for proof of concept
_NewTestItems = DataAccessLibrary.GetNextDataChunk(db);
}
changeListener.Start(string.Format(NOTIFY_SQL));
/* END OF EVENT HANDLING CODE */
};
// Now everything has been set up.... start it running.
changeListener.Start(string.Format(NOTIFY_SQL));
}
}
}
使用语句
命名空间Sample4.TestItemRequest
{
公共部分类MyExampleSsender:Iwanttorunshenbus开始和停止
{
私有字符串NOTIFY_SQL=@“使用(NOLOCK)从[dbo].[Test]中选择[id],其中ISNULL([Status],'N')='N';
public void Start(){u StartListening();}
public void Stop(){抛出新的NotImplementedException();}
私有无效
{
var db=新模型.TestEntities();
//使用指定的连接字符串实例化新的DBListener
var changeListener=新数据库changeListener(ConfigurationManager.ConnectionString[“TestConnection”].ConnectionString);
//将大括号内的代码分配给DBListener的onChange事件
changeListener.OnChange+=()=>
{
/*事件处理代码的开始*/
//这对EF数据模型使用LINQ来获取更改的记录
IEnumerable _NewTestItems=DataAccessLibrary.GetInitialDataSet(db);
而(_NewTestItems.Count()>0)
{
foreach(新测试中的变量qq)
{
//如果需要,进行一些处理
var newtesttem=new NewTestStarted(){…从qq对象设置属性…};
发布(新测试项目);
}
//因为可能会添加许多新行,所以我将以小批量方式获取它们,直到完成。
//也许最好使用RX来实现这一点,但这将用于概念验证
_NewTestItems=DataAccessLibrary.GetNextDataChunk(db);
}
changeListener.Start(string.Format(NOTIFY_SQL));
/*事件处理代码结束*/
};
//现在一切都已设置好…开始运行。
changeListener.Start(string.Format(NOTIFY_SQL));
}
}
}
重要OnChange事件触发会导致侦听器停止监视。它基本上是一个单事件通知程序。处理完事件后,要做的最后一件事是重新启动DBListener。(您可以在事件处理注释结尾前的一行中看到这一点)
您需要添加对System.Data和System.Data.DataSetExtensions的引用
目前这个项目仍然是概念验证,所以我很清楚上面的内容可以有所改进。还要记住,我必须去掉公司特定的代码,所以可能会有bug。将其视为模板,而不是工作示例
我也不知道这是否是放置代码的正确位置-这就是我今天在StackOverflow上的部分原因;寻找更好的ServiceBus主机代码示例。无论我的代码有什么缺陷,到目前为止,解决方案都非常有效,并且也满足了您的目标
不要太担心ServiceBroker方面的事情。一旦您设置好它,根据教程,SQLDependency会为您处理细节。只有一件小事:删除Stop方法实现中的NotImplementedException,否则每次启动时端点都会崩溃shutdown@Mauro-当您“实现接口”时,VS会自动将其添加。我在为发布清理代码时没有注意到这一点,它可能仍在我的代码中,因为它仍在开发/测试中。谢谢你来接我;我会忘记的,它会咬我的@AnyoneStillReading此-my NOTIFY_SQL中的WITH(NOLOCK)与SQLDependency不兼容。我认为这是从一个初始的测试版本,我已经更新。这