Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 同一应用程序是否可以同时作为发布服务器/订阅服务器和NServiceBus?_C#_Msmq_Nservicebus - Fatal编程技术网

C# 同一应用程序是否可以同时作为发布服务器/订阅服务器和NServiceBus?

C# 同一应用程序是否可以同时作为发布服务器/订阅服务器和NServiceBus?,c#,msmq,nservicebus,C#,Msmq,Nservicebus,我不熟悉消息传递体系结构,所以我可能走错了方向。但我想通过解决一个小问题,在我的团队中慢慢引入NServiceBus 议程中的任命有国家。两个用户可以在同一个应用程序中查看同一议程中的同一约会。他们通过中央服务器上的远程会话启动此应用程序。因此,如果用户1更新约会的状态,我希望用户2看到新状态“实时” 为了模拟这一点或进行概念验证(如果您愿意),我制作了一个新的控制台应用程序。通过NuGet,我同时获得了NServiceBus和NServiceBus.Host,因为从文档中我了解到,我需要这两个

我不熟悉消息传递体系结构,所以我可能走错了方向。但我想通过解决一个小问题,在我的团队中慢慢引入NServiceBus

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

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

在类程序方法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();
}
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);
    }
}
public class AppointmentStateChangedHandler:IHandleMessages{
公共无效句柄(Events.AppointmentStateChanged消息){
WriteLine(“AppointmentID:{0},更改为状态:{1}”,
message.AppointmentID,
message.NewState);
}
}
如果我启动一个控制台应用程序,一切正常。我看到处理程序处理该事件。但如果我尝试启动第二个控制台应用程序,它会崩溃:System.Messaging.MessageQueueException(请求的操作超时已过期)。所以我一定是做错了什么,让我再次猜测我不理解更高层次的东西。谁能给我指一下正确的方向吗

更新 除AgendaUpdate.Events命名空间中的事件类外,所有内容都位于AgendaUpdate命名空间中

更新2 采取的步骤:

  • 复制的AgendaUpdate解决方案(到AgendaUpdate文件夹)
  • 在副本中,我将App.Config中的MessageEndpointMappings端点属性更改为“AgendaUpdates2” 我收到MSMQ异常:“队列不存在或您没有足够的权限执行该操作”
  • 在副本中,我将这行代码添加到EndPointConfig:configuration.EndpointName(“AgendaUpdates2”); 我收到MSMQ异常:“队列不存在或您没有足够的权限执行该操作”
  • 在副本中,我将这行代码添加到Program类的Main方法中: configuration.EndpointName(“AgendaUpdates2”); 按此键后再次获取原始异常

-->我用原始和复制的解决方案启动了2个VisualStudio来测试它。然后在IDE中启动两个控制台应用程序

我不太清楚为什么会出现这种特殊的异常,但我可以解释为什么您尝试的操作失败了。问题在于发布服务器和订阅服务器不在同一个应用程序中(这是可能的,并且可能很有用);问题是您在同一台计算机上运行同一应用程序的两个实例

NServiceBus依赖于队列技术(在您的例子中是MSMQ),要使一切正常工作,每个应用程序都需要有自己独特的队列。当您启动两个相同的实例时,两个实例都试图共享同一队列

为了让场景正常工作,更好地理解排队是如何工作的,您可以修改以下几点:

  • 更改第二个实例的
  • 在单独的计算机上运行第二个实例
  • 将发布服务器和订阅服务器分离到单独的进程中
  • 无论您选择哪种方式,都需要调整MessageEndpointMappings(在使用者/订阅者上),以反映主机/发布者队列所在的位置(消息类型的“所有者”):

    根据您的更新进行编辑

    我知道这是一个测试设置/概念验证,但将这两种部署(代码相同)视为发布服务器/主机和订阅服务器/客户端仍然很有用。因此,让我们将原始的调用为主机,将副本调用为客户端。我假设您不想让每个人都订阅另一个(至少在这个基本测试中是这样)

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

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

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

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

    在副本中,我将这行代码添加到程序类的Main方法:configuration.EndpointName(“AgendaUpdates2”);按此键后再次获得原始异常

    我最初没有注意到这一点,但您不需要配置端点两次。我相信不会调用EndPointConfig,因为它仅在通过NSB主机可执行文件托管时使用。您可能只需要删除这个类


    这听起来很合理,但请记住,如果您的副本是订阅者,则不应发布副本,因此在副本启动后不要按任何键(仅按原件中的键)。

    如果您希望发布者同时也是消息的接收者,请在配置中指定此项


    这一点在中有清楚的解释,其中问题的解决方案完全在文章的末尾。

    在问题中,您省略了用于指定端点名称的名称空间。正如Phil所说,确保两者都有自己独特的队列和spe
    public class AppointmentStateChanged: IEvent {
        public int AppointmentID { get; set; }
        public string NewState { get; set; }
    }
    
    public class AppointmentStateChangedHandler : IHandleMessages<Events.AppointmentStateChanged> {
    public void Handle(Events.AppointmentStateChanged message) {
            Console.WriteLine("AppointmentID: {0}, changed to state: {1}", 
                message.AppointmentID, 
                message.NewState);
        }
    }