Reputation: 13397
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
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