Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autofac Property Injection in Nancy Module

I am using Autofac for DI and i have NacyModule like:

public class TestModule: NancyModule
{
    public ISessionFactory SessionFactory { get; set; }
    public IMapper Mapper { get; set; }

    public TestModule(ITestRepository testRepository)
    {
        Get("hello", _ => "hello world");
    }
}

My AutoFac configuration

In Startup.cs

    var builder = new ContainerBuilder();

                builder.RegisterModule(new ServicesModule());
                builder.RegisterModule(new NHibernateModule(configuration.GetConnectionString("DefaultConnection")));
                builder.RegisterModule(new AutomapperModule());
                builder.Populate(services);
                container = builder.Build();

                return new AutofacServiceProvider(container);

in ServiceModule.cs 

    builder.RegisterAssemblyTypes(ThisAssembly)
                               .Where(t => new[]
                        {
                           "Processor",
                            "Process",
                            "Checker",
                            "Indexer",
                            "Searcher",
                            "Translator",
                            "Mapper",
                            "Exporter",
                            "Repository"         }.Any(y =>
                        {
                            var a = t.Name;
                            return a.EndsWith(y);
                        }))
                    .AsSelf()
                    .AsImplementedInterfaces()
                    .PropertiesAutowired()
                    .InstancePerLifetimeScope();

in NHibernateModule.cs

    builder.Register(c => CreateConfiguration(connectionString)).SingleInstance();
    builder.Register(c => c.Resolve<Configuration>().BuildSessionFactory()).As<ISessionFactory>().SingleInstance().PropertiesAutowired();

And in my nancy bootstraper I have something like this

 public class Bootstrapper : AutofacNancyBootstrapper
    {
        private static readonly ILogger logger = LogManager.GetLogger(typeof(Bootstrapper).FullName);

        private readonly ILifetimeScope _container;

        public Bootstrapper(ILifetimeScope container)
        {

            _container = container;
        }

        protected override ILifetimeScope GetApplicationContainer()
        {
            return _container;
        }

        public override void Configure(INancyEnvironment environment)
        {
            base.Configure(environment);

            environment.Tracing(false, true);
        }

        protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context)
        {
            container.Update(builder =>
            {
                builder.Register(c =>
                {
                    var sf = c.Resolve<ISessionFactory>();
                    return new Lazy<NHibernate.ISession>(() =>
                    {
                        var s = sf.OpenSession();
                        s.BeginTransaction();
                        return s;
                    });
                }).InstancePerLifetimeScope();

                builder.Register(c => c.Resolve<Lazy<NHibernate.ISession>>().Value).As<NHibernate.ISession>();
            });
        }
}

I now about constructor injection, works ok, and property injection works ok in other classes, but not works in nancy modules

Note I tried adding .PropertiesAutowired() in ConfigureRequestContainer after the container update

thanks.

like image 299
Adriano Scazzola Avatar asked Nov 22 '25 16:11

Adriano Scazzola


1 Answers

The AutofacNancyBootstrapper class automatically register the module in Autofac even if the service is already registered :

AutofacNancyBootstrapper.cs

protected override INancyModule GetModule(ILifetimeScope container, Type moduleType)
{
    return container.Update(builder => builder.RegisterType(moduleType)
                                              .As<INancyModule>())
                    .Resolve<INancyModule>();
}

With the default implementation the module is always registered and PropertiesAutoWired is not applied.

To change this, you can override the method like this :

protected override INancyModule GetModule(ILifetimeScope container, Type moduleType)
{
    return container.Update(builder => builder.RegisterType(moduleType)
                                              .As<INancyModule>())
                    .Resolve<INancyModule>()
                    .PropertiesAutoWired();
}

Or change it like this :

protected override INancyModule GetModule(ILifetimeScope container, Type moduleType)
{
    INancyModule module = null;

    if (container.IsRegistered(moduleType))
    {
        module = container.Resolve(moduleType) as INancyModule;
    }
    else
    {
        IEnumerable<IComponentRegistration> registrations = container.ComponentRegistry.RegistrationsFor(new TypedService(typeof(INancyModule)));
        IComponentRegistration registration = registrations.FirstOrDefault(r => r.Activator.LimitType == moduleType);
        if (registration != null)
        {
            module = container.ResolveComponent(registration, Enumerable.Empty<Parameter>()) as INancyModule;
        }
        else
        {
            module = base.GetModule(container, moduleType);
        }
    }

    return module;
}

and then register the module in your composition root

builder.RegisterType<TestModule>()
       .As<INancyModule>()
       .PropertiesAutoWired()
like image 97
Cyril Durand Avatar answered Nov 24 '25 05:11

Cyril Durand



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!