I have an application which might needs to connect to multiple databases. But each module will only connect to one db. So I though it might make sense to isolate the db into each module so each module will get its own db auto resolved and I don't need to bother with named registration. But to my astonishment, it seems that Autofac's module is more a code module than a logical module (am I wrong here?): IA
[Test]
public void test_module_can_act_as_scope_container()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new Module1());
IContainer c = builder.Build();
var o = c.ResolveNamed<CB>("One");
Assert.That(o.A.Name, Is.EqualTo("One"));
builder = new ContainerBuilder();
builder.RegisterModule(new Module1());
builder.RegisterModule(new Module2());
c = builder.Build();
var t = c.ResolveNamed<CB>("One");
Assert.That(t.A.Name, Is.EqualTo("Two"));
}
And the interfaces/Modules used:
public interface IA
{
string Name { get; set; }
}
public class CA : IA
{
public string Name { get; set; }
}
public class CB
{
public CB(IA a)
{
A = a;
}
public IA A { get; private set; }
}
public class Module1 : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new CA() { Name = "One" }).As<IA>();
builder.RegisterType<CB>().Named("One", typeof(CB));
}
}
public class Module2 : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new CA() { Name = "Two" }).As<IA>();
builder.RegisterType<CB>().Named("Two", typeof(CB));
}
}
Yes, you're kind of correct.
Modules serve only for splitting configuration into somewhat independent parts. They do not scope configuration in any way. Having modules is actually the same as if you merged all modules' Load methods' code into a single configuration method and then built the container.
In your case your Module2 actually overrides the registration for IA interface from Module1.
I've also been interested in finding a solution to the problem. I've come to the following approach:
Keyed service
var key = new object();
builder.Register(c => new CA() { Name = "Two" }).Keyed<IA>(key);
builder.RegisterType<CB>().Named("Two", typeof(CB))
.WithParameter(new ResolvedParameter(
(pi, ctx) => pi.Type == typeof(IA),
(pi, ctx) => ctx.ResolveKeyed<IA>(key)
));
Pros:
You can control which IA instances will be injected in each module.
Contras:
It's quite a lot of code
It does not make IA component 'internal' to the module - other modules can still resolve it using simple Resolve<IA>. Modules aren't isolated.
Hope this helps
UPDATE
In some cases it may be easier, and frankly more correct from design point of view, to make it this way:
Delegate registration
builder.Register(ctx => new CB(new CA { Name = "Two" }))
.Named("Two", typeof(CB));
Pros:
You don't expose your module-specific CA to other modules
Contras:
If CA and CB have complex dependencies and a lot of constructor parameters, you'll end up with mess of constructing code
If you need to use CA in several places inside a module, you'll have to find a way to avoid copy-pasting
Nested Container instances
And yet another option is having an independent Container inside each module. This way all modules will be able to have their private container configurations. However, AFAIK, Autofac doesn't provide any built-in means to somehow link several Container instances. Although I suppose implementing this should not be very difficult.
You could use nestet lifetime scopes. These form a hierarchy in which subscopes can resolve services registered in superscopes. Additionally, you can register unique services in each subscope, like this:
var cb = new ContainerBuilder();
cb.RegisterModule<CommonModule>();
var master = cb.Build();
var subscope1 = master.BeginLifetimeScope(cb2 => cb2.RegisterModule<Module1>());
var subscope2 = master.BeginLifetimeScope(cb2 => cb2.RegisterModule<Module2>());
With this setup, services in Module1 will only be available to instances resolved from subscope1.
Related
I'm using Autofac.
I'm trying to register 2 classes with same interface using decorator pattern.
public interface IDoable
{
string Do();
}
public class Decoree : IDoable
{
public string Do()
{
return "decoree";
}
}
public class Decorator : IDoable
{
public IDoable InnerDecoree { get; set; }
public Decorator(IDoable doable)
{
this.InnerDecoree = doable;
}
public string Do()
{
return InnerDecoree.Do() + "decorator";
}
}
I'd like to use container for resolving two types for 2 different cases:
IDoable where I'd expect that instance would be instance of Decorator
and for specific Decoree where I really need to resolve specific Decoree instance.
Only way how I can achieve it is using following code:
[Fact]
public void Both()
{
var builder = new ContainerBuilder();
builder.RegisterType<Decoree>()
.Named<IDoable>("decoree")
.SingleInstance();
builder.RegisterType<Decoree>() // but this is not right I'd like to register it on line above somehow...
.AsSelf()
.SingleInstance();
builder.RegisterType<Decorator>()
.Named<IDoable>("decorator")
.SingleInstance();
builder.RegisterDecorator<IDoable>(
(c, inner) => c.ResolveNamed<IDoable>("decorator", TypedParameter.From(inner)), "decoree")
.As<IDoable>();
var container = builder.Build();
Assert.IsType<Decoree>(container.Resolve<Decoree>());
Assert.False(container.IsRegistered<Decorator>());
Assert.IsType<Decorator>(container.Resolve<IDoable>());
var decoree = container.Resolve<Decoree>();
var decorator = container.Resolve<IDoable>();
var doable = ((Decorator)decorator).InnerDecoree;
Assert.Same(decoree, doable); // FALSE :(
}
The thing is that I'd really love the last assertion to be true :) so It's same instance.
Basically my question is: Is it possible to register type both ways using named and type ?
Because you aren't specifying a scope in your registration, you are getting a different instance of Decoree every time it gets resolved. I would try something like
builder.RegisterType<Decoree>()
.Named<IDoable>("decoree").SingleInstance();
In addition, you might need to combine your 2 registrations of the Decoree type:
builder.RegisterType<Decoree>()
.Named<IDoable>("decoree")
.AsSelf()
.SingleInstance();
I have a Autofac module as below
public class ServiceInjector:Module
{
protected override void Load(ContainerBuilder builder)
{
// many registrations and type looking up here
...
// One of the registration, say t which is found
// in above looking, is a resource consuming type
builder.RegisterType(t).As<ITimeConsume>();
// ...
}
}
And this module is used in a ServiceClass:
public class ServiceClass
{
static IContainer _ioc;
public ServiceClass()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ServiceInjector>();
_ioc = builder.Build();
}
public void InvokeService()
{
using(var scope = _ioc.BeginLifetimeScope())
{
ITimeConsume obj = scope.Resolve<ITimeConsume>(...);
var result = obj.DoTimeConsumingJob(...);
// do something about result here ...
}
}
}
My questions is: how do I test ServiceClass by mocking (Moq) ITimeConsume class ? Here I try to write a test below:
public void Test()
{
Mock<ITimeConsume> moc = GetMockObj(...);
// How can I inject moc.Object into ServiceInjector module,
// so that ServiceClass can use this mock object ?
}
If this is not possible for the way, what's a better design for mocking the time consuming class which can also be injected?
**
Update:
**
Thanks #dubs and #OldFox hints. I think the key is that the Autofac injector should be initialized externally instead of internal controlled. So I leverage 'On Fly' building capability of Autofac.ILifetimeScope and design ServiceClass constructor with a LifeTime scope parameter. With this design I can on-flying registering any service in the unit test as below example:
using(var scope = Ioc.BeginLifetimeScope(
builder => builder.RegisterInstance(mockObject).As<ITimeConsume>())
In the current design you cannot inject your mock object.
The simplest solution with the least changes is to add an Internal Cto'r to ServiceClass:
internal ServiceClass(IContainer ioc)
{
_ioc = ioc;
}
Then use the attributte InternalsVisibleTo to enable the using of the C`tor in your test class.
In the arrange/setup/testInit phase initialize your class under test with the container which contains the mock object:
[SetUp]
public void TestInit()
{
Mock<ITimeConsume> moc = GetMockObj(...);
builder.RegisterInstance(moc).As<ITimeConsume>();
...
...
_target = new ServiceClass(builder.Build());
}
Personally I have multiple container instances. One for each endpoint.
Test project
public class AutofacLoader
{
public static void Configure()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ServiceProject.ServiceInjector>();
builder.RegisterModule<LocalTestProject.AutofacModule>();
Container = builder.Build();
}
public static IContainer Container { get; set; }
}
The local test project autofac module is then free to override the service project module with specific registrations.
If more than one component exposes the same service, Autofac will use the last registered component as the default provider of that service: http://autofac.readthedocs.org/en/latest/register/registration.html#default-registrations
Test class
public void Test()
{
AutofacLoader.Configure();
var x = AutofacLoader.Container.Resolve<ITimeConsume>();
}
How is it possible to use Autofac's Modules combined with the Multitenant package?
This is my bootstrapping part for Autofac:
var builder = new ContainerBuilder();
// only very basic common registrations here...
// everything else is in modules
// Register the Autofac module for xml configuration as last
// module to allow (emergency) overrides.
builder.RegisterModule(new ConfigurationSettingsReader());
// create container for IoC
this.container = builder.Build();
// check for tenant strategy -> if exists, go multi-tenant
if (this.container.IsRegistered<ITenantIdentificationStrategy>())
{
var tenantIdentificationStrategy = this.container
.Resolve<ITenantIdentificationStrategy>();
this.container = new MultitenantContainer(tenantIdentificationStrategy,
this.container);
// how to use xml modules instead of manually register at this point?
}
else
{ ... }
I don't want to call something like
container.ConfigureTenant('1', b => b.RegisterType<Tenant1Dependency>()
.As<IDependency>()
.InstancePerDependency());
within the bootstrapper (which don't need to know something about this).
Instead I want to do something like this:
public class TenantModule : Module
{
protected override void Load(ContainerBuilder builder)
{
container.ConfigureTenant('1', b => b.RegisterType<Tenant1Dependency>()
.As<IDependency>()
.InstancePerDependency());
container.ConfigureTenant('2', b => b.RegisterType<Tenant2Dependency>()
.As<IDependency>()
.InstancePerDependency());
...
My first idea was to check when registering something for a special tenant:
public class TenantModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register((c, p) => {
var s = c.Resolve<ITenantIdentificationStrategy>();
if (s != null)
{
var id = s.IdentifyTenant<string>();
...
}
});
I could check the id and register only if id fits, but what to return if id is not matching? null? DoNothingObject? Looks strange/horrible in code to me and something like
builder.Register("1", (context, parameters) => ...
feels more natural. But I don't know how to achieve this out of the box with Autofac. Did I miss something? How did you solved that problem?
Missed the point that ConfigureTenant also passes the containerBuilder which allows the registration of a tenant specific ConfigurationSectionReader. So an option is to have an additional customer/tenant specific ConfigurationSection:
mtc.ConfigureTenant("mytenant1",
containerBuilder =>
{
containerBuilder.RegisterModule(new ConfigurationSettingsReader("mytenant1"));
}
);
mtc.ConfigureTenant("mytenant2",
containerBuilder =>
{
containerBuilder.RegisterModule(new ConfigurationSettingsReader("mytenant2"));
}
);
This also leads me to the point that I can resolve the tenant identification strategy first, get the identifier and make only the registrations for the current tenant (like a customer specific bootstrap):
var tenantIdentificationStrategy = container.Resolve<ITenantIdentificationStrategy>();
var tid = tenantIdentificationStrategy.IdentifyTenant<string>();
mtc.ConfigureTenant(tid ,
containerBuilder =>
{
containerBuilder.RegisterModule(new ConfigurationSettingsReader(tid));
// or something like that which identifies the tenant config section
}
);
Or I could put this into a simple foreach to make registrations for all available tenants (but this sounds curious in most scenarios here because only one tenant will be resolved at time at its a bootstrapping part, maybe for other special cases worth to mention).
Any better ideas? I'll vote up for better ideas... ;-)
Is it possible to register a component conditionally on an other component's state? Something like:
ContainerBuilder.RegisterConditionally<T>(
Func<IComponentContext, bool>,
Func<IComponentContext, T>);
I've found that prior to V2 of autofac one could use a "Register().OnlyIf()" construction that seemed like the one I'm looking for. I would like such feature to conditionally override a default registration.
class CommonRegistrations
{
public virtual void Register(ContainderBuilder builder)
{
builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
builder.RegisterType<DefaultFoo>().As<IFoo>();
}
}
class SpecificRegistrations : CommonRegistrations
{
public virtual void Register(ContainerBuilder builder)
{
base.Register(builder);
builder.ConditionalyRegister(
ctx => ctx.Resolve<ISettings>().ReallyUseSpecificFoo,
ctx => new SpecificFoo()).As<IFoo>();
}
}
...
var builder = new ContainerBuilder();
var registrations = new SpecificRegistrations();
registrations.Register(builder);
var container = builder.Build();
IFoo foo = container.Resolve<IFoo>();
The foo will be according to ISettings.ReallyUseSpecificFoo either instance of DefaultFoo or instance of SpecificFoo.
Thank you.
There is no way to perform conditional registration at the container level based on container contents. The trouble is that you would need to resolve something in the container in order to determine what gets registered in the container, which then could technically affect whether you wanted to register the thing in the first place. Chicken/egg circular dependency problem.
You can, however, register things conditionally into nested lifetime scopes. Most integration points (like ASP.NET) resolve out of nested lifetime scopes (like an HTTP-request-length lifetime scope). You can register things on the fly into nested lifetime scopes and that might solve your problem.
var builder = new ContainerBuilder();
builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
builder.RegisterType<DefaultFoo>().As<IFoo>();
var container = builder.Build();
var settings = container.Resolve<ISettings>();
using(var scope =
container.BeginLifetimeScope(b => {
if(settings.ReallyUseSpecificFoo)
{
b.RegisterType<SpecificFoo>().As<IFoo>();
}
})
{
// Resolve things from the nested lifetime scope - it will
// use the overrides. This will get the SpecificFoo if the
// configuration setting is true.
var foo = scope.Resolve<IFoo>();
}
Another option you have is to make the registration a lambda. It might make the registration itself more complex but it's an option you could consider.
var builder = new ContainerBuilder();
builder.Register(ctx => {
var settings = ctx.Resolve<ISettings>();
if(settings.ReallyUseSpecificFoo)
{
return new SpecificFoo();
}
return new DefaultFoo();
}).As<IFoo>();
If manual construction there isn't appealing, you could pass it through Autofac, too.
var builder = new ContainerBuilder();
// Register the IFoo types - but NOT "As<IFoo>"
builder.RegisterType<DefaultFoo>();
builder.RegisterType<SpecificFoo>();
// In the lambda use Resolve<T> to get the instances.
builder.Register(ctx => {
var settings = ctx.Resolve<ISettings>();
if(settings.ReallyUseSpecificFoo)
{
return ctx.Resolve<SpecificFoo>();
}
return ctx.Resolve<DefaultFoo>();
}).As<IFoo>();
Yet another option is to update an existing container after being built. In this case, you avoid the chicken/egg scenario by actually building the container, using it, and changing registrations after the fact.
var builder = new ContainerBuilder();
builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
builder.RegisterType<DefaultFoo>().As<IFoo>();
var container = builder.Build();
var settings = container.Resolve<ISettings>();
if(settings.ReallyUseSpecificFoo)
{
var updater = new ContainerBuilder();
updater.RegisterType<SpecificFoo>().As<IFoo>();
updater.Update(container);
}
Finally, you might consider XML configuration. Given the registration is dependent on some sort of configuration setting, you might consider using Autofac's XML configuration support. That way, instead of trying to resolve something out of an un-built container to conditionally register something else, you could just specify the right thing to register using the XML configuration and register the correct thing the first time.
I'm struggling with how to organize my Autofac component registrations in modules given that some of the modules themselves have dependencies.
I've implemented an abstraction of configuration data (i.e. web.config) in an interface:
interface IConfigurationProvider
{
T GetSection<T>(string sectionName)
where T : System.Configuration.ConfigurationSection;
}
along with implementations for ASP.NET (WebConfigurationProvider) and "desktop" applications (ExeConfigurationProvider).
Some of my autofac modules then require an IConfigurationProvider as a constructor parameter, but some don't:
class DependentModule : Module
{
public DependentModule(IConfigurationProvider config)
{
_config = config;
}
protected override void Load(ContainerBuilder builder)
{
var configSection = _config.GetSection<CustomConfigSection>("customSection");
builder.RegisterType(configSection.TypeFromConfig);
}
private readonly IConfigurationProvider _config;
}
class IndependentModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(/* other stuff not based on configuration */);
}
}
Since the RegisterType() extension method doesn't accept a registration delegate (Func<IComponentContext, T>), like Register() does, I can't register the IConfigurationProvider up-front and then resolve it when I go to register the type specified in the configuration, something like:
// this would be nice...
builder.RegisterType(c => c.Resolve<IConfigurationProvider>().GetSection<CustomConfigSection>("sectionName").TypeFromConfig);
This means that I need to be able to register modules with and without a dependency on IConfigurationProvider.
It's obvious how to manually instantiate each module and register it:
IConfigurationProvider configProvider = ...;
var builder = new ContainerBuilder();
builder.RegisterModule(new DependentModule(configProvider));
builder.RegisterModule(new IndependentModule());
using (var container = builder.Build())
{
...
}
But I don't want to manually instantiate my modules - I want to scan assemblies for modules and register them automatically (as discussed in this question). So I have to use reflection to scan the assembly for IModule types, and use Activator.CreateInstance to make registerable instances. But how do I know whether or not to pass an IConfigurationProvider as a constructor parameter. And what happens when other modules have additional or different dependencies?
There's got to be a more straightforward way of accomplishing the basic task: register a type specified in some configuration provided via an interface, right? So how do I do that?
You could do something like this:
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Autofac.Core;
using NUnit.Framework;
namespace Yo_dawg
{
[TestFixture]
public class I_heard_you_like_containers
{
[Test]
public void So_we_built_a_container_to_build_your_container()
{
var modules = GetModules();
Assert.That(modules.Length, Is.EqualTo(4));
var builder = new ContainerBuilder();
foreach (var module in modules)
builder.RegisterModule(module);
var container = builder.Build();
}
private IModule[] GetModules()
{
var builder = new ContainerBuilder();
var configurationProvider = new ConfigurationProvider();
builder.RegisterInstance(configurationProvider).AsImplementedInterfaces().ExternallyOwned();
builder.RegisterAssemblyTypes(GetType().Assembly)
.Where(t => t.IsAssignableTo<IModule>())
.AsImplementedInterfaces();
using (var container = builder.Build())
return container.Resolve<IEnumerable<IModule>>().ToArray();
}
}
public class ModuleA : Module
{
public ModuleA(IConfigurationProvider config)
{
}
}
public class ModuleB : Module
{
public ModuleB(IConfigurationProvider config)
{
}
}
public class ModuleC : Module
{
}
public class ModuleD : Module
{
}
public interface IConfigurationProvider
{
}
public class ConfigurationProvider : IConfigurationProvider
{
}
}
For this scenario, Autofac's own XML configuration seems to cover the scenarios you're targeting. Adding a new IConfigurationProvider mechanism seems like reinventing this functionality already provided by the container. The basics are documented at: https://code.google.com/p/autofac/wiki/XmlConfiguration. The configuration syntax has in-built support for modules.
There's a nice alternative by Paul Stovell that allows modules to be registered in code yet receive parameters from config - see: http://www.paulstovell.com/convention-configuration. Hope this helps!