0

I'm a bit at a loss here. I'm developing a hosted NServicebus (v4.7) windows service and using Autofac (v3.5) to do my own type resolution. Given the NServicebus documentation I thought it was possible to add my own container in NServicebus's endpoint configuration. However no matter what I do, I can't get it to work. My current endpointconfig is the following:

using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using Autofac;
using HyFlo.Base;
using NServiceBus;
using NServiceBus.ObjectBuilder.Autofac;
using NServiceBus.ObjectBuilder.Common.Config;

namespace HyFlo.Service
{
    /// <summary>
    ///     EndpointConfig
    /// </summary>
    public class EndpointConfig : IConfigureThisEndpoint, INeedInitialization, AsA_Publisher
    {
        public void Init()
        {
            TraceWriter.Info("Scannning for Hyflo assemblies .. ");

            var hyfloAssemblies = Directory.GetFiles(Directory.GetCurrentDirectory(), "Hyflo.*.dll",
                                                     SearchOption.TopDirectoryOnly);

            TraceWriter.Info("Initializing Autofac with assemblies .. ");
            try
            {
                var builder = new ContainerBuilder();
                Assembly[] allAssemblies = hyfloAssemblies.Select(Assembly.LoadFile).ToArray();
                builder.RegisterAssemblyTypes(allAssemblies).AsImplementedInterfaces().InstancePerLifetimeScope();
                IContainer container = builder.Build();

                TraceWriter.Trace(
                    String.Format(
                        "Found {0} assembl{1}. Configuring NServicebus to use Autofac preinitialized with these assembl{1} ..",
                        allAssemblies.Count(), allAssemblies.Count() == 1 ? "y" : "ies"));

                Configure.With().UsingContainer(new AutofacObjectBuilder(container));
            }
            catch (Exception ex)
            {
                TraceWriter.Trace(String.Format("Exception occurred during initialization. Exception is: {0}\n{1}",
                                                ex.Message, ex.StackTrace));
            }

            TraceWriter.Info("Initializing database en msmqsubscription .. ");

            string databusBasePath = ConfigurationManager.AppSettings["DataBusBasePath"] ?? "";

            TraceWriter.Trace(String.Format("Setting Databus's basepath to '{0}' ..", databusBasePath));
            Configure.With().FileShareDataBus(databusBasePath);

            Configure.With().MsmqSubscriptionStorage();
        }
    }
}

This code itself works however when the NServicebus initialisation continues an exception pops up:

Failed to execute installers: System.InvalidOperationException: Cannot configure properties for a type that hasn't been configured yet: NServiceBus.Un icast.UnicastBus at NServiceBus.ObjectBuilder.Autofac.AutofacObjectBuilder.ConfigureProperty(Type component, String property, Object value) in c:\BuildAgent\work\1b 05a2fea6e4cd32\src\NServiceBus.Core\ObjectBuilder\Autofac\AutofacObjectBuilder.cs:line 0 at NServiceBus.ObjectBuilder.Common.CommonObjectBuilder.ConfigureProperty[T](String propertyName, Object value) in c:\BuildAgent\work\1b05a2fea6e4c d32\src\NServiceBus.Core\ObjectBuilder\Common\CommonObjectBuilder.cs:line 110 at NServiceBus.Unicast.Config.FinalizeUnicastBusConfiguration.RegisterMessageOwnersAndBusAddress(IEnumerable'1 knownMessages) in c:\BuildAgent\work \1b05a2fea6e4cd32\src\NServiceBus.Core\Unicast\Config\FinalizeUnicastBusConfiguration.cs:line 57 at NServiceBus.Unicast.Config.FinalizeUnicastBusConfiguration.FinalizeConfiguration() in c:\BuildAgent\work\1b05a2fea6e4cd32\src\NServiceBus.Core\U nicast\Config\FinalizeUnicastBusConfiguration.cs:line 24 at NServiceBus.Configure.<>c__DisplayClass23`1.b__20(Type t) in c:\BuildAgent\work\1b05a2fea6e4cd32\src\NServiceBus.Core\Configu re.cs:line 555 at System.Collections.Generic.List'1.ForEach(Action'1 action) at NServiceBus.Configure.ActivateAndInvoke[T](Action'1 action, Nullable'1 thresholdForWarning) in c:\BuildAgent\work\1b05a2fea6e4cd32\src\NServiceB us.Core\Configure.cs:line 561 at NServiceBus.Configure.Initialize() in c:\BuildAgent\work\1b05a2fea6e4cd32\src\NServiceBus.Core\Configure.cs:line 361 at NServiceBus.Hosting.Windows.Installers.WindowsInstaller.RunInstall() in c:\BuildAgent\work\1b05a2fea6e4cd32\src\NServiceBus.Hosting.Windows\Inst allers\WindowsInstaller.cs:line 38

No matter what I do, for some reason NServicebus's initialisation can't continue. It looks like my own Autofac container isn't properly configured in NServicebus by using the Configure.With().UsingContainer() method but I've tried all kind of options but every time it boils down to the same exception that is being thrown. Any ideas what I'm doing wrong here?

  • Tried changing the interface to IWantCustomInitialization as was suggested in http://stackoverflow.com/questions/18621897/nservicebus-configuration-with-custom-container. The code then works but for some reason NServicebus doesn't inject the IBus instance anymore. Now the classes that handle messages have an empty IBus instance. Hmm .. – Richard Flapper Jun 26 '15 at 08:02

2 Answers2

0

I found the answer to the problem. I scanned pretty much all DLL's to be included in Nservicebus's Autofac container. This also includes the DLL that contains the endpointconfig. Now when I exclude the DLL containing the endpoint, all goes well. I've now isolated pretty much all classes from the endpointconfig-DLL except for the message handlers. And now all goes well!

  • You don't have to register your handler classes with Autofac yourself. NServiceBus will do this for you when you. Configure.With() means all assemblies will be scanned for interfaces that are known to NServiceBus and those types will be registered. In your Autofac initialization you only need to register your own dependencies. It is generally not a good practice to just register all types in all assemblies. It is much better to work with Autofac modules and register just what you need. – Alexey Zimarev Jul 06 '15 at 09:20
  • Interesting! Didn't know that but I'll see if I can do that. My earlier Autofac initialisation indeed did contain the registration of only the types I needed but requires a lot of maintenance as the current codebase is still a bit in flux. I had pages upon pages of initialisation. The current one is easier in the current phase when adding or removing classes. I am planning though on changing the above shown implementation with something of an attribute-markup implementation that lets me specify which classes I want to include and which not. – Richard Flapper Jul 06 '15 at 09:31
  • I prefer using modules, one module per assembly. Modules registration can be done by assembly scanning using builder.RegisterAssemblyModules. In modules Load I register types that I need, including types by name match or implemented interface match. This gives me more granular control over dependencies registration. Concerning NServiceBus. Configure.With accepts list of assemblies to scan and if this parameter is omitted, all assemblies will be scanned. – Alexey Zimarev Jul 06 '15 at 11:11
  • Hmm .. that does sound interesting. You mean defining a class that inherits from Autofac.Module in each assembly and do all initialisation in its .Load method? Interesting indeed. Will look into that. Thanks for the pointer! – Richard Flapper Jul 06 '15 at 11:31
-1

Try changing the code like this:

Configure configure = Configure.With();
// rest of container initialization
configure.AutofacBuilder(container);
// other stuff
configure.FileShareDataBus(databusBasePath);
configure.MsmqSubscriptionStorage();

and see if it works.

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
Daniel Marbach
  • 2,294
  • 12
  • 15
  • Unfortunately the same errors. When applied to the IWantCustomInitialization interface it installs the service but upon starting the service, the Bus instance isn't initialised. And when applied to the INeedInitialization interface it gives the same exception as I displayed earlier. Could it be that Autofac 3.5.2 isn't supported by NServicebus 4.7.5 (and using NServicebus.Autofac 4.7.5)? – Richard Flapper Jun 29 '15 at 07:58
  • We use Autofac 3.5.2 with NServiceBus 4.7.5 and it works fine. – Alexey Zimarev Jul 06 '15 at 09:14
  • Thanks Alexey! Yes, you're right. It wasn't because Autofac or NServicebus but it was all because I scanned all assemblies to register my own types including the assembly that contained the endpoint. Separating the endpoint from the rest of my dependencies solved the issue. – Richard Flapper Jul 06 '15 at 09:37