1

Our framework has the following structure:

  • webapi project
  • basic CQRS project
  • Nhibnerate configuration project

The solution uses Autofac to wire up all the classes. The api will load all assemblies and register all the modules in those assemblies.

Most of the modules simply look for all interfaces and implementations and that works great, using instance per request.

The CQRS is a very basic example of command and query handlers. As there will be lots in the future and they may have various dependencies I do not want to manually write a factory to get all the handlers (or to add reference to each one in the API).

To address the above I have a Command / Query HandlerFactory which takes in the command or query it wants to run. Using reflection it finds the type of handler for it and uses a base handlerResolver so it can get a new instance of the handler. to do this I pass in ILifetimeScope to the resolver so it is only done in one place. (I am aware that referencing the lifetimescope is gernally an anti pattern, but my feeling was that if I am going to end up with hundreds of commands and queries I would end up with a horrible factory that takes all possible dependencies, and using autofac to wire it up is cleaner).

If everything is left as instance per request this all works, all classes are resolved and the commands and queries will run. The issue is that for every API request the NHibnernate configuration gets rebuilt which takes around 1.5 seconds on my machine. which means almost every request will take up to 2 seconds to respond.

What I would like to do is be able to register the NHibnerate configuration and sessionFactory as a singleton (as it will not have any sensitive / user data related information), so that it is created as little as possible. Also to leave all the handlers and other classes as per request so they are independent and disposed of as soon as possible.

the main class to hook up the web api:

public static class AutoFacSetup
{
    public static IContainer Create()
    {
        var builder = new ContainerBuilder();

        // this is to insist we use hbm config rather than fluent as there are two implentations of IConfigurationFactory
        builder.RegisterType<OurHbmConfigurationFactory>().SingleInstance();

        var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();

        // Register your Web API controllers.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
        builder.RegisterAssemblyModules(assemblies);

        builder.RegisterSelf();
        var container = builder.Build();

        return container;
    }

    public static void RegisterSelf(this ContainerBuilder builder)
    {
        IContainer container = null;
        builder.Register(c => container).AsSelf().SingleInstance();
        builder.RegisterBuildCallback(c => container = c);
    }
}

an example of one of the module classes:

public class AutoFacInstallerModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        var assembly = GetType().Assembly;
        builder
            .RegisterAssemblyTypes(assembly)
            .Except<NhibernateDbConnectionFactory>(x => x.SingleInstance())
            .Except<MySessionFactory>(x => x.SingleInstance())
            .AsImplementedInterfaces()
            .InstancePerRequest();
    }
}
Jon
  • 15,110
  • 28
  • 92
  • 132
  • I have an answer, but not as keen. I have removed all singleinstance references and turned all of them into having public static properties and only create them if they are null (with private setters) – Jon Feb 05 '18 at 15:13

0 Answers0