同一个应用程序可以同时是NServiceBus的发布者/订阅者吗?

时间:2015-10-23 07:57:10

标签: c# msmq nservicebus

我是消息传递架构的新手,所以我可能会采用错误的方式。但我想通过解决一个小问题在我的团队中慢慢介绍NServiceBus。

议程中的任命有州。两个用户可能在相同的应用程序中查看相同日程中的相同约会。他们通过中央服务器上的远程会话启动此应用程序。因此,如果用户1更新约会的状态,我希望用户2看到新的状态'实时'。

如果要模拟这个或做出概念验证,我做了一个新的控制台应用程序。通过NuGet我得到了NServiceBus和NServiceBus.Host,因为我从文档中了解到我需要两者。我知道在生产代码中不建议将所有内容放在同一个程序集中,但发布者和订阅者很可能最终会在同一个程序集中... ...

在类Program方法Main中我编写了以下代码:

BusConfiguration configuration = new BusConfiguration();

configuration.UsePersistence<InMemoryPersistence>();
configuration.UseSerialization<XmlSerializer>();
configuration.UseTransport<MsmqTransport>();
configuration.TimeToWaitBeforeTriggeringCriticalErrorOnTimeoutOutages(new TimeSpan(1, 0, 0));
ConventionsBuilder conventions = configuration.Conventions();
conventions.DefiningEventsAs(t => t.Namespace != null
    && t.Namespace.Contains("Events"));

using (IStartableBus bus = Bus.Create(configuration))
{
    bus.Start();

    Console.WriteLine("Press key");
    Console.ReadKey();

    bus.Publish<Events.AppointmentStateChanged>(a =>
    {
        a.AppointmentID = 1;
        a.NewState = "New state";
    });

    Console.WriteLine("Event published.");
    Console.ReadKey();
}

在类EndPointConfig方法中定制我添加:

configuration.UsePersistence<InMemoryPersistence>();
configuration.UseSerialization<XmlSerializer>();
configuration.UseTransport<MsmqTransport>();
ConventionsBuilder conventions = configuration.Conventions();
conventions.DefiningEventsAs(t => t.Namespace != null
    && t.Namespace.Contains("Events"));

AppointmentStateChanged是Events文件夹中的一个简单类,如下所示:

public class AppointmentStateChanged: IEvent {
    public int AppointmentID { get; set; }
    public string NewState { get; set; }
}

AppointmentStateChangedHandler是事件处理程序:

public class AppointmentStateChangedHandler : IHandleMessages<Events.AppointmentStateChanged> {
public void Handle(Events.AppointmentStateChanged message) {
        Console.WriteLine("AppointmentID: {0}, changed to state: {1}", 
            message.AppointmentID, 
            message.NewState);
    }
}

如果我启动一个控制台应用程序一切正常。我看到处理程序处理事件。但是,如果我尝试启动第二个控制台应用程序,它会崩溃:System.Messaging.MessageQueueException(请求的操作的超时已过期)。因此,我必须做错事,让我猜测我不会在更高层次上理解某些事情。有人能指出我正确的方向吗?

更新 Everthing位于命名空间AgendaUpdates中,但AgendaUpdates.Events命名空间中的事件类除外。

更新2 采取的步骤:

  • 复制的AgendaUpdates解决方案(至AgendaUpdates2文件夹)
  • 在副本中,我将App.Config中的MessageEndpointMappings更改为&#34; AgendaUpdates2&#34; 我收到了MSMQ异常:&#34;队列不存在或者您没有足够的权限来执行操作&#34;
  • 在副本中,我将这行代码添加到EndPointConfig:configuration.EndpointName(&#34; AgendaUpdates2&#34;); 我收到了MSMQ异常:&#34;队列不存在或者您没有足够的权限来执行操作&#34;
  • 在副本中,我将这行代码添加到Program类的Main方法中: configuration.EndpointName(&#34; AgendaUpdates2&#34); 按键后再次获得原始异常。

- &GT;我通过使用原始和复制的解决方案启动2个视觉工作室来测试它。然后在IDE中启动两个控制台应用程序。

2 个答案:

答案 0 :(得分:3)

我不确定为什么你会得到特定的异常,但我可以解释为什么你要做的事情失败了。问题是在同一个应用程序中没有发布者和订阅者(​​这是可能的并且可能有用);问题是你在同一台机器上运行同一个应用程序的两个实例。

NServiceBus依赖于排队技术(在您的情况下为MSMQ),并且为了使一切正常工作,每个应用程序都需要拥有自己的唯一队列。当您启动两个相同的实例时,两者都试图共享同一个队列。

有一些事情你可以修改以使你的场景工作,并更好地了解排队的工作原理:

  1. 更改第二个实例的EndPointName
  2. 在另一台计算机上运行第二个实例
  3. 将发布商和订阅者分隔为单独的流程
  4. 无论您采用哪种方式,都需要调整MessageEndpointMappings(在使用者/订阅者身上)以反映主机/发布者队列所在的位置(消息类型的“所有者”):

    http://docs.particular.net/nservicebus/messaging/message-owner#configuring-endpoint-mapping

    根据您的更新进行修改

    我知道这是一个测试设置/概念验证,但考虑这两个部署(相同代码)与发布者/主机和订阅者/客户端仍然有用。因此,让我们将原始主机称为客户端并复制客户端。我假设您不希望每个订阅另一个(至少对于此基本测试)。

    此外,请确保在计算机上以管理员身份运行这两个IDE。我不确定这是不是在干扰。

    在副本中,我将App.Config中的MessageEndpointMappings更改为“AgendaUpdates2”,我得到了MSMQ异常:“队列不存在或者您没有足够的权限来执行操作”

    由于副本是客户端,因此您希望将其映射指向主机。所以这应该是“AgendaUpdates”(省略“2”)。

    在副本中,我将这行代码添加到EndPointConfig:configuration.EndpointName(“AgendaUpdates2”);我得到了MSMQ异常:“队列不存在或者您没有足够的权限来执行操作”

    在副本中,我将这行代码添加到Program类的Main方法中:configuration.EndpointName(“AgendaUpdates2”);按键

    后再次获得原始异常

    我之前没有注意到这一点,但您不需要两次配置端点。我相信你的EndPointConfig没有被调用,因为它仅在通过NSB主机可执行文件进行托管时使用。您可以删除此课程。

    这听起来很合理,但请记住,如果是订户,您的副本不应该发布,所以在启动后不要按任何键(只按原始键)。

答案 1 :(得分:1)

如果您希望发布者也是消息的接收者,您希望在配置中指定它。

this article清楚地解释了这一点,您的问题的解决方案完全在文章的最后。