Alf Kåre Lefdal
Alf Kåre Lefdal

Reputation: 703

NServiceBus Saga Persistence

We have an NServiceBus service configured to run sagas. With InMemory-persistence everything runs fine. When trying to change the profile to NServiceBus.Integration, we get an error when starting the service.

Endpoint configuration:

public class MyEndpoint : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
    private IContainer _container;

    public void Init()
    {
        log4net.Config.XmlConfigurator.Configure();
        SetupStructureMap();

        Configure.With()
            .Log4Net()
            .StructureMapBuilder(_container)
            .Sagas()
            .XmlSerializer();
    }

    private void SetupStructureMap()
    {
        [...]
    }
}

Error message:

    FATAL 2012-01-18 11:11:52,197  2640ms GenericHost            Start              - FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.

      * Database was not configured through Database method.
     ---> System.ArgumentException: The number of generic arguments provided doesn't equal the arity of the generic type definition.
    Parameter name: instantiation
       at System.RuntimeType.MakeGenericType(Type[] instantiation)
       at FluentNHibernate.Automapping.AutoMapManyToMany.GetInverseProperty(PropertyInfo property)
       at FluentNHibernate.Automapping.AutoMapManyToMany.MapsProperty(PropertyInfo property)
       at FluentNHibernate.Automapping.AutoMapper.TryToMapProperty(ClassMappingBase mapping, PropertyInfo property, IList`1 mappedProperties)
       at FluentNHibernate.Automapping.AutoMapper.MapEverythingInClass(ClassMappingBase mapping, Type entityType, IList`1 mappedProperties)
       at FluentNHibernate.Automapping.AutoMapper.MergeMap(Type classType, ClassMappingBase mapping, IList`1 mappedProperties)
       at FluentNHibernate.Automapping.AutoMapper.Map(Type classType, List`1 types)
       at FluentNHibernate.Automapping.AutoPersistenceModel.AddMapping(Type type)
       at FluentNHibernate.Automapping.AutoPersistenceModel.CompileMappings()
       at FluentNHibernate.Cfg.AutoMappingsContainer.Apply(Configuration cfg)
       at FluentNHibernate.Cfg.MappingConfiguration.Apply(Configuration cfg)
       at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration()
       --- End of inner exception stack trace ---
       at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration()
       at NServiceBus.SagaPersisters.NHibernate.Config.Internal.SessionFactoryBuilder.UpdateDatabaseSchemaUsing(FluentConfiguration fluentConfiguration)
       at NServiceBus.SagaPersisters.NHibernate.Config.Internal.SessionFactoryBuilder.Build(IDictionary`2 nhibernateProperties, Boolean updateSchema)
       at NServiceBus.ConfigureNHibernateSagaPersister.NHibernateSagaPersister(Configure config, IDictionary`2 nhibernateProperties, Boolean autoUpdateSchema)
       at NServiceBus.ConfigureNHibernateSagaPersister.NHibernateSagaPersisterWithSQLiteAndAutomaticSchemaGeneration(Configure config)
       at NServiceBus.Host.Internal.ProfileHandlers.IntegrationProfileHandler.NServiceBus.IHandleProfile.ProfileActivated()
       at NServiceBus.Host.Internal.ProfileManager.<ActivateProfileHandlers>b__14(IHandleProfile hp)
       at System.Collections.Generic.List`1.ForEach(Action`1 action)
       at NServiceBus.Host.Internal.ProfileManager.ActivateProfileHandlers()
       at NServiceBus.Host.Internal.GenericHost.Start()

      * Database was not configured through Database method.

Configuration file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="MsmqTransportConfig" type="NServiceBus.Config.MsmqTransportConfig, NServiceBus.Core" />
        <section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" requirePermission="false" />
        <section name="MsmqSubscriptionStorageConfig" type="NServiceBus.Config.MsmqSubscriptionStorageConfig,NServiceBus.Core" />
    </configSections>
    <MsmqTransportConfig InputQueue="MyQueue" ErrorQueue="MyQueueError" NumberOfWorkerThreads="1" MaxRetries="5" />

    <UnicastBusConfig>
        <MessageEndpointMappings>
            <add Messages="My.MessageContracts" Endpoint="MyQueue" />
        </MessageEndpointMappings>
    </UnicastBusConfig>
    <log4net debug="false">
        <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
            <file value="C:\Log\My.log" />
            <appendToFile value="true" />
            <rollingStyle value="Size" />
            <maxSizeRollBackups value="10" />
            <maximumFileSize value="10MB" />
            <staticLogFileName value="true" />
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
            </layout>
        </appender>
        <root>
            <level value="INFO" />
            <appender-ref ref="RollingLogFileAppender" />
        </root>
    </log4net>
</configuration>

Upvotes: 1

Views: 2476

Answers (2)

Alf K&#229;re Lefdal
Alf K&#229;re Lefdal

Reputation: 703

The problem was, as Andreas touched upon, on persisting the SagaData-class using NHibernate/Fluent NHibernate.

Just to summarize all the things that were wrong:

  • In order to use the profile NServicebus.Integration, you need to add a reference to SQLite (use NuGet)
  • In order to use the profile NServiceBus.Production, you need to set up connection to the database in app.config, as Adam showed in his answer.
  • In order to use both these two profiles, your SagaData-class must be playing by the rules of NHibernate:
    • All properties must be virtual
    • The class must not be sealed
    • The same goes for the type of all properties

All this is for NServiceBus 2.6. In 3.0, which is in Beta6 now, they use RavenDB instead, with no binding to NHibernate or SQLite. How the transition from 2.6 to 3.0 is, I do not know yet, but I think this is the way we are going on this project.

Upvotes: 0

Adam Fyles
Adam Fyles

Reputation: 6050

Looks like you are missing the following from the config, it is in the app.config of the OrderService in the samples:

<section name="DBSubscriptionStorageConfig" type="NServiceBus.Config.DBSubscriptionStorageConfig, NServiceBus.Core" />
<section name="NHibernateSagaPersisterConfig" type="NServiceBus.Config.NHibernateSagaPersisterConfig, NServiceBus.Core" />

<DBSubscriptionStorageConfig>
    <NHibernateProperties>
      <add Key="connection.provider" Value="NHibernate.Connection.DriverConnectionProvider"/>
      <add Key="connection.driver_class" Value="NHibernate.Driver.SQLite20Driver"/>
      <add Key="connection.connection_string" Value="Data Source=.\Subscriptions.sqlite;Version=3;New=True;"/>
      <add Key="dialect" Value="NHibernate.Dialect.SQLiteDialect"/>
    </NHibernateProperties>
  </DBSubscriptionStorageConfig>

<NHibernateSagaPersisterConfig>
    <NHibernateProperties>
      <add Key="connection.provider" Value="NHibernate.Connection.DriverConnectionProvider"/>
      <add Key="connection.driver_class" Value="NHibernate.Driver.SqlClientDriver"/>
      <add Key="connection.connection_string" Value="Server=localhost;initial catalog=NServiceBus;Integrated Security=SSPI"/>
      <add Key="dialect" Value="NHibernate.Dialect.MsSql2000Dialect"/>
    </NHibernateProperties>
  </NHibernateSagaPersisterConfig>

Upvotes: 2

Related Questions