使用NHibernate的NServiceBus Sagas - 无法连接到远程服务器

时间:2012-10-12 22:18:22

标签: nservicebus

我正在尝试使用NHibernate持久性设置NServiceBus Sagas,但我认为我配置错误,因为我在127.0.0.1:8080连接到服务时出错。我能够让我的传奇处理命令消息,但几秒钟后,控制台窗口中出现以下错误消息,然后再次触发相同的命令,导致再次调用saga中的处理程序。只要我允许应用程序运行,就会重复发生这种情况。我可以告诉NHibernate连接到我的数据库,因为它为saga数据创建了一个表,但该表中没有任何内容。

我认为持续存在saga数据时出现错误,我的猜测是它可能尝试使用默认的RavenDb saga持久性,但我不确定为什么会这样。

我收到的错误消息如下:

  

WARN   NServiceBus.Unicast.Transport.Transactional.TransactionalTransport   [(null)]<(null)> - 未能提出“收到的运输消息”事件   对于ID = 3753b476-7501-4fd8-90d0-b10aee95a578 \ 22314的消息   System.Net.WebException:无法连接到远程服务器--->   System.Net.Sockets.SocketException:无法建立连接   因为目标机器主动拒绝它127.0.0.1:8080 at   System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot,   SocketAddress(socketAddress)at   System.Net.Sockets.Socket.InternalConnect(EndPoint remoteEP)at   System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure,   插座s4,插座s6,插座& socket,IPAddress&地址,   ConnectSocketState状态,IAsyncResult asyncResult,Exception&   例外)---内部异常堆栈跟踪结束--- at   NServiceBus.Unicast.UnicastBus.HandleTransportMessage(IBuilder   childBuilder,TransportMessage msg)at   NServiceBus.Unicast.UnicastBus.TransportMessageReceived(对象发送者,   TransportMessageReceivedEventArgs e)at   System.EventHandler`1.Invoke(Object sender,TEventArgs e)at   NServiceBus.Unicast.Transport.Transactional.TransactionalTransport.OnTransportMessageReceived(TransportMessage   MSG)

我试图使用的传奇样本(这里没什么特别的,无论我是否真的在Handle方法中做某事,都会发生同样的事情):

public class ItemSaga : Saga<ItemData>, IAmStartedByMessages<CreateItemCommand>
{
    public void Handle(CreateItemCommand message)
    {

    }
}

public class ItemData : ISagaEntity
{
    public Guid Id { get; set; }
    public string Originator { get; set; }
    public string OriginalMessageId { get; set; }
}

我的端点配置如下所示:

public class EndpointConfig : IConfigureThisEndpoint, AsA_Publisher, IWantCustomInitialization
{


    public void Init()
    {

        var container = new UnityContainer();
        container.AddNewExtension<Domain.UnityExtension>();

        Configure.With()
            .UnityBuilder(container)
            .JsonSerializer()
            .Log4Net()
            .MsmqSubscriptionStorage()
            .MsmqTransport()
                .PurgeOnStartup(true)
            .UnicastBus()
                .ImpersonateSender(false)
            .DisableTimeoutManager()
            .NHibernateSagaPersister()
            .CreateBus()
            .Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install()); 
    }
}

我的app.config看起来像这样:

<MessageForwardingInCaseOfFaultConfig ErrorQueue="error"/>
  <MsmqTransportConfig NumberOfWorkerThreads="1" MaxRetries="5"/>

  <NHibernateSagaPersisterConfig UpdateSchema="true">
    <NHibernateProperties>
      <add Key="connection.provider" Value="NHibernate.Connection.DriverConnectionProvider"/>
      <add Key="connection.driver_class" Value="NHibernate.Driver.Sql2008ClientDriver"/>
      <add Key="connection.connection_string" Value="Data Source=(localdb)\v11.0;Integrated Security=True;AttachDbFileName=|DataDirectory|\App_Data\EventStore.mdf"/>
      <add Key="dialect" Value="NHibernate.Dialect.MsSql2012Dialect"/>
    </NHibernateProperties>
  </NHibernateSagaPersisterConfig>

  <connectionStrings>
    <add name="EventStore" connectionString="Data Source=(localdb)\v11.0;Integrated Security=True;AttachDbFileName=|DataDirectory|\App_Data\EventStore.mdf"
      providerName="System.Data.SqlClient" />
  </connectionStrings>

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
     <dependentAssembly>
        <assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" />
        <bindingRedirect oldVersion="0.0.0.0-3.3.0.4000" newVersion="3.3.1.4000" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

只是几个笔记:

这是来自我用来测试此功能的示例应用。它使用附加到localdb的本地数据库文件,但是我使用SQL Server 2012的完整应用程序表现出相同的行为。我还必须为NHibernate添加一个dependdenteAssembly条目,因为NServiceBus.NHibernate NuGet包当前绑定到较旧的程序集版本(截至本文)。

正如您所看到的,我也使用Unity作为我的IOC,但我也使用Ninject复制了一个项目。我使用EventStore进行域名存储,效​​果很好。我有命令处理程序处理命令并通过EventStore发布事件以由其他进程处理。但是,我已经尝试禁用所有那些只留下我的Saga作为命令处理程序的人,我仍然得到同样的错误。

有没有人对我可能做错了什么有任何想法?

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法。使用内置的NServiceBus配置文件似乎是一个问题。我没有在主机的命令行参数中指定配置文件,因此默认情况下它正在加载NServiceBus.Production配置文件。默认情况下,Production配置文件使用RavenDB进行所有持久性。

查看GitHub上的NServiceBus源,生产配置文件处理程序在ProfileActivated方法中包含以下内容:

Configure.Instance.RavenPersistence();

if (!Configure.Instance.Configurer.HasComponent<ISagaPersister>())
    Configure.Instance.RavenSagaPersister();

if (!Configure.Instance.Configurer.HasComponent<IManageMessageFailures>())
    Configure.Instance.MessageForwardingInCaseOfFault();

if (Config is AsA_Publisher && !Configure.Instance.Configurer.HasComponent<ISubscriptionStorage>())
    Configure.Instance.RavenSubscriptionStorage();

这里需要注意几点:

  • 该配置文件将始终调用RavenPersistence() 配置实例。我没有深入研究那种内在运作方式 方法,看看它是否会实际绕过配置Raven if other 持久性已经定义,但它将始终运行此方法。
  • 当我附加到NServiceBus源并通过调试时 这段代码,在第二行HasComponent返回 false导致运行RavenSagaPersister配置。这个 即使我在端点中定义了NHibernateSagaPerister也会发生 配置。

我不确定这种行为是否是设计,错误或我的错误配置。但是我的解决方法是创建自己的个人资料。我不得不将NHibernate配置调用从我的端点配置移动到我的新配置文件,但是一旦我这样做,我就能够使用NHibernate持久性而没有错误。

我的自定义配置文件如下所示(我从Production配置文件的日志处理程序中借用了日志记录处理程序):

public class MyProfile : IProfile
{

}

internal class MyProfileProfileHandler : IHandleProfile<MyProfile>, IWantTheEndpointConfig
{
    void IHandleProfile.ProfileActivated()
    {
        Configure.Instance.NHibernateUnitOfWork();
        Configure.Instance.NHibernateSagaPersister();
        Configure.Instance.DBSubcriptionStorage();
        Configure.Instance.UseNHibernateTimeoutPersister();
    }

    public IConfigureThisEndpoint Config { get; set; }
}

public class MyProfileLoggingHandler : IConfigureLoggingForProfile<MyProfile>
{
    void IConfigureLogging.Configure(IConfigureThisEndpoint specifier)
    {
        SetLoggingLibrary.Log4Net<RollingFileAppender>(null,
            a =>
            {
                a.CountDirection = 1;
                a.DatePattern = "yyyy-MM-dd";
                a.RollingStyle = RollingFileAppender.RollingMode.Composite;
                a.MaxFileSize = 1024 * 1024;
                a.MaxSizeRollBackups = 10;
                a.LockingModel = new FileAppender.MinimalLock();
                a.StaticLogFileName = true;
                a.File = "logfile";
                a.AppendToFile = true;
            });

        if (GetStdHandle(STD_OUTPUT_HANDLE) == IntPtr.Zero)
            return;

        SetLoggingLibrary.Log4Net<ColoredConsoleAppender>(null,
          a =>
          {
              LiteLoggingHandler.PrepareColors(a);
              a.Threshold = Level.Info;
          }
      );
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);
    const int STD_OUTPUT_HANDLE = -11;
}

最后一点,我还必须根据标准的NHibernate实践将我的saga数据对象的所有属性设置为虚拟。一旦系统实际使用NHibernate,这就变得非常明显了。

public class ItemData : ISagaEntity
{
    public virtual Guid Id { get; set; }
    public virtual string Originator { get; set; }
    public virtual string OriginalMessageId { get; set; }
}

这是一个很长的解释,但希望它能帮助其他人走出困境。如果有人对更好的方法有所建议,或者使用配置文件的正确方法,请告诉我们!