阅读SQL Server Broker消息并使用NServiceBus发布它们

时间:2014-12-01 09:44:14

标签: nservicebus

我是NServiceBus的新手,在我们的一个项目中,我们希望完成以下任务 -

  1. 每当在Sql server中修改表数据时,构造一条消息并插入sql server broker queue
  2. 使用NServiceBus
  3. 读取代理队列消息
  4. 将该邮件作为另一个事件再次发布,以便其他订阅者 可以处理它。
  5. 现在是第2点,我没有太多线索,如何完成它。

    我已经引用了以下帖子,之后我能够在代理队列中输入消息,但无法在我们的项目中与NServiceBus集成,因为NServiceBus库是旧版本,并且不推荐使用许多方法。因此,将它们与当前版本一起使用会变得非常麻烦,或者如果我以不正当的方式使用它们。

    http://www.nullreference.se/2010/12/06/using-nservicebus-and-servicebroker-net-part-2 https://github.com/jdaigle/servicebroker.net

    任何有关正确方法的帮助都是非常宝贵的。

    感谢。

2 个答案:

答案 0 :(得分:2)

我正在使用当前版本的nServiceBus(5),VS2013和SQL Server 2008.我使用this tutorial创建了一个数据库更改侦听器,它使用SQL Server对象代理和SQLDependency来监视对特定的更改表。 (注意:在SQL Server的更高版本中可能会弃用此选项。)

SQL依赖关系允许您使用所有基本SQL功能的广泛选择,尽管您需要了解some restrictions。我稍微修改了教程中的代码,以提供更好的错误信息:

    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项目的相关部分]包含两个“Run as Host”端点,其中一个端点发布事件消息。第二个端点处理消息。发布者已经设置为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));

        }
    }
}

重要 OnChange事件触发会导致侦听器停止监听。它基本上是一个单一的事件通知器。处理完事件后,最后要做的就是重启DBListener。 (您可以在END OF EVENT HANDLING评论之前的行中看到这一点。)

您需要添加对System.Data和System.Data.DataSetExtensions的引用。

目前这个项目仍然是概念证明,所以我很清楚上面的内容可以有所改善。另外请记住,我必须删除公司特定的代码,因此可能存在错误。将其视为模板,而不是工作示例。

我也不知道这是否是放置代码的正确位置 - 这也是我今天使用StackOverflow的部分原因;寻找更好的ServiceBus主机代码示例。无论我的代码有什么缺陷,解决方案都能非常有效地工作 - 到目前为止 - 并且也符合您的目标。

不要过于担心ServiceBroker方面的问题。一旦你完成了设置,根据教程,SQLDependency会为你处理细节。

答案 1 :(得分:0)

ServiceBroker Transport非常陈旧,不再支持,据我记忆所及。 一个可能的解决方案是&#34;监控&#34;使用类似SqlDependency(http://msdn.microsoft.com/en-us/library/62xk7953(v=vs.110).aspx)之类的端点代码中的有趣表格,然后将消息推送到相关队列中。

的.m