r3plica
r3plica

Reputation: 13397

Autofac resolving dependencies

I am really new to autofac and having issues. I am using Web API and I have set my module up like this:

public class CormarModule : Module
{


    // Fields
    private readonly string _connectionStringName;
    private readonly connectionType _connection;

    /// <summary>
    /// Default constructor
    /// </summary>
    public CormarModule() {
        _connectionStringName =  ConfigurationManager.AppSettings["ConnectionStringName"];
        _connection = _connectionStringName.ToUpper().Contains("LIVE") ? connectionType.Live : connectionType.Test;
    }

    protected override void Load(ContainerBuilder builder)
    {

        // Singletons
        builder.RegisterType<DatabaseContext>().As<DatabaseContext>().SingleInstance();
        builder.RegisterType<UnitOfWork<DatabaseContext>>().As<IUnitOfWork>().SingleInstance();
        builder.Register(c => new OracleUnitOfWork(_connectionStringName)).As<IOracleUnitOfWork>().SingleInstance();
        builder.Register(c => new AdvancedEncryptionStandardProvider(ConfigurationManager.AppSettings["rm:key"], ConfigurationManager.AppSettings["rm:secret"])).As<IAdvancedEncryptionStandardProvider>().SingleInstance();

        // Register our services         
        builder.RegisterType<AccountService>().As<IAccountService>();
        builder.RegisterType<DeliveryInformationService>().As<IDeliveryInformationService>();
        builder.RegisterType<EmailService>().As<IEmailService>();
        builder.RegisterType<LogService>().As<ILogService>();
        builder.RegisterType<OrderService>().As<IOrderService>();
        builder.RegisterType<OrderLineService>().As<IOrderLineService>();
        builder.RegisterType<PaymentHistoryService>().As<IPaymentHistoryService>();
        builder.RegisterType<PrincipleProvider>().As<IPrincipleProvider>();
        builder.RegisterType<ProductService>().As<IProductService>();
        builder.RegisterType<RefreshTokenService>().As<IRefreshTokenService>();
        builder.RegisterType<StockService>().As<IStockService>();
        builder.Register(c => new UserStore<User>(c.Resolve<DatabaseContext>())).As<IUserStore<User>>();

        // Single instance
        builder.RegisterType<OAuthProvider>().As<OAuthProvider>();
        builder.RegisterType<LogProvider>().As<ILogProvider>();
        builder.RegisterType<RefreshTokenProvider>().As<IAuthenticationTokenProvider>();
        builder.Register(c => new SendGridProvider(c.Resolve<IUnitOfWork>(), c.Resolve<IEmailService>(), ConfigurationManager.AppSettings["SendGridApiKey"])).As<ISendGridProvider>();
        builder.Register(c => new UserProvider(_connectionStringName, c.Resolve<IUserStore<User>>(), c.Resolve<IAdvancedEncryptionStandardProvider>(), c.Resolve<ISendGridProvider>())).As<IUserProvider>();

        // Per request
        builder.RegisterType<DeliveryInformationProvider>().As<IDeliveryInformationProvider>().InstancePerRequest();
        builder.RegisterType<JournalProvider>().As<IJournalProvider>().InstancePerRequest();
        builder.RegisterType<StockProvider>().As<IStockProvider>().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies).InstancePerRequest();

        builder.Register(c => new AccountProvider(_connection, c.Resolve<IAccountService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>(), c.Resolve<IPaymentHistoryService>())).As<IAccountProvider>().InstancePerRequest();
        builder.Register(c => new ProductProvider(_connection, c.Resolve<IProductService>())).As<IProductProvider>().InstancePerRequest();
        builder.Register(c => new OrderProvider(_connection, c.Resolve<IOrderService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>())).As<IOrderProvider>().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies).InstancePerRequest();
        builder.Register(c => new OrderLineProvider(_connection, c.Resolve<IOrderLineService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>())).As<IOrderLineProvider>().InstancePerRequest();
    }
}

I am struggling with the different scopes. A little background before I explain my issue.

Each Provider has a required Service and each Controller has one or more Providers injected. Each Provider could have an optional Provider which should only be resolved when a method invokes that provider.

The problem I have is I don't know how to set that up. I was going to inject the lifetime scope into the constructor and in the method, resolve the required Provider, but I have read this is bad practice, plus it would create a new instance. I would like to use one instance per request, but only if it is need in that request.

I hope that makes sense and I hope someone can help!

Upvotes: 0

Views: 227

Answers (1)

Alberto Chiesa
Alberto Chiesa

Reputation: 7360

IMO, you're doing pretty good.

What you need is to take a dependency on a Func<Provider>. When you ask Autofac a Func<> it returns a factory method, to be called instead of .Resolve<Provider>.

See here and here for documentation.

You can write it this way:

private OptionalProvider _instance;
private Func<OptionalProvider> _providerGetter;

public OptionalProvider Prov
{
    get { return _instance ?? (_instance = _providerGetter()); }
}

public MyProvider(Func<OptionalProvider> getter)
{
    _providerGetter = getter;
}

public void MethodRequiringOptionalProvider()
{
    // just use property Prov and let Autofac handle the rest
}

Another suggestion: instead of injecting directly the _connection string parameter, just create a CormarConfig class, to be registered with .RegisterInstance to store all your configuration options. This way you just call RegisterType and let Autofac resolve all the type parameters (you get rid of those ugly Resolve calls).

If all your services inherit from a common ancestor or implement a common interface, you can register them all via Assembly Scanning and AsImplementedInterfaces. You would get rid of all the clutter in your module.

Upvotes: 1

Related Questions