Warning, long post ahead.
I've been thinking a lot about this lately and I'm struggling to find a satisfying solution here. I will be using C# and autofac for the examples.
The problem
IoC is great for constructing large trees of stateless services. I resolve services and pass the data only to the method calls. Great.
Sometimes, I want to pass a data parameter into the constructor of a service. That's what factories are for. Instead of resolving the service I resolve its factory and call create method with the parameter to get my service. Little more work but OK.
From time to time, I want my services to resolve to the same instance within a certain scope. Autofac provides InstancePerLifeTimeScope() which is very handy. It allows me to always resolve to the same instance within an execution sub-tree. Good.
And there are times when I want to combine both approaches. I want data parameter in constructor and have have the instances scoped. I have not found a satisfying way to accomplish this.
Solutions
1. Initialize method
Instead of passing data into the constructor, just pass it to Initialize method.
Interface:
interface IMyService
{
void Initialize(Data data);
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public void Initialize(Data data)
{
mData = data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Usage:
var myService = context.Resolve<IMyService>();
myService.Init(data);
// somewhere else
var myService = context.Resolve<IMyService>();
After resolving the service for the first time and calling Initialize I can happily resolve within the same context and get the same initialized instance. I don't like the fact that before calling Initialize I have an unusable object. There is a danger that the instance will be resolved and used somewhere else before I call Initialize().
2. Holder pattern
This is a pattern that holds a reference to the data object and instead of injecting the data object itself I inject the holder object.
Interface:
interface IMyService
{
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public MyService(IDataHolder dataHolder)
{
mData = dataHolder.Data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>();
builder.RegisterType<DataHolder>().As<IDataHolder>().InstancePerLifetimeScope();
Usage:
var holder = context.Resolve<IDataHolder>();
holder.Data = data;
// somewhere else
var myService = context.Resolve<IMyService>();
This is a little bit better as I moved the responsibility of holding an instance to a different class. I can now use the holder in other services too. Other advantage is that I can hot swap data in holder if necessary. I don't like the fact that it obfuscates the code and adds another interface I have to mock during testing.
3. Let container hold the instance
Interface:
interface IMyService
{
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public MyService(Data data)
{
mData = dataHolder.Data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Usage:
var myServiceFactory = context.Resolve<Func<Data, IMyService>>();
myServiceFactory(data);
// somewhere else
var myService = context.Resolve<IMyService>();
That's right. I don't store the result of a factory call anywhere, because autofac stores it for me. This is pretty surprising to anybody who will read the code. I'm not sure if autofac was even meant to be used like this. Nice thing about this is that I need neither an extra initialize method nor extra class for holding instance.
Question
What is your take on this? How do you handle a situation with run-time data parameters and lifetime scoping? Am I missing a better approach?
Autofac now supports this out of the box with an extension to the lifetime scopes. The BeginLifetimeScope() method has an overload that takes an Action<ContainerBuilder> that allows for adding new registrations specific to only that lifetime scope. So for the given example it would look something like:
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
using(var scope = container.BeginLifetimeScope(
builder =>
{
builder.RegisterInstance(new Data(....));
}))
{
// References to 'IMyService' will always be resolved to the same instance within this lifetime scop
// References to 'Data' will be resolved to the instance registered just for this lifetime scope.
var svc = scope.Resolve<IMyService>();
}
Most of the time, runtime data is the non static info you need to pass in any process, like x in a math function, so the easiest way to deal with it is using a parameter in the function:
class MyService : IMyService
{
public MyService(){}
public void DoStuff(Data mData)
{
//...
}
}
var myService = context.Resolve<IMyService>();
myService.DoStuff(data);
But, assuming your example is just a example and you are asking because your class need to keep runtime data to run more processes and you don't wanna to pass the same argument in every function:
1.- If you don't loose the scope of the runtime data in every Resolve you can resolve with TypedParameter:
Ej:
//initilization
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
//any point of your app
Data mData = new Data("runtimeData"); // must to be accesible in every place you Resolve
using(var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<IMyService>(new TypedParameter(typeof(Data), mData));
service.DoStuff();
}
using(var scope = container.BeginLifetimeScope())
{
var service2 = scope.Resolve<IMyService>(new TypedParameter(typeof(Data), mData));
service2.DoStuff();
}
2.- If you don't have a reference to runtime data in every place you are resolving you can RegisterInstance when and where you create runtime data. Autofac should inyect mData instance thanks to Direct Depency Policy
//initilization
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
//where you create or modify runtime data. When runtime data changes you have to update the container again.
var mData = new Data("runtimeData");
updatedBuilder= new ContainerBuilder();
updatedBuilder.RegisterInstance(mData).As<Data>
updatedBuilder.Update(builder);
//in any point of your app
using(var scope = updatedBuilder.BeginLifetimeScope())
{
var service = scope.Resolve<IMyService>();
service.DoStuff();
}
//in any other point of your app
using(var scope = updatedBuilder.BeginLifetimeScope())
{
var service2 = scope.Resolve<IMyService>();
service2.DoStuff();
}
My take on this is that you've done about as good as you can do. The only niggle that I have about it is that Autofac doesn't really do a great job of helping you manage those lifetime scopes, so you're stuck calling their BeginLifetimeScope somewhere. And they can be nested.
Ninject, on the other hand, does some really cool stuff that doesn't require turning your brain inside-out. Their named scope extension makes it possible for you to create a (gasp) named scope and bind the lifetime of objects within that scope. If you are using factories (clearly you are, judging from the question) you'll also want to use the context preservation extension, so that stuff activated out of factories gets the lifetime management from the named scope that the factory was activated within. Bindings wind up looking something like this:
var scopeName = "Your Name Here";
Bind<TopLevelObject>().ToSelf().DefinesNamedScope(ScopeName);
Bind<ISomeScopedService>().To<SomeScopedService>().InNamedScope(ScopeName);
// A minor bit of gymnastics here for factory-activated types to use
// the context-preservation extension.
Bind<FactoryActivatedType>().ToSelf().InNamedScope(ScopeName);
Bind<IFactoryActivatedType>().ToMethod(x => x.ContextPreservingGet<FactoryActivatedType>());
The nice part about this is that the scope of those bindings is specifically tied to the named scope rather than just being tied to whatever the nearest lifetime scope up the chain is. IMHO, it makes the lifetimes of those objects much more predictable.
Many IoC frameworks support registration of a factory function (or lambda expression), that takes as one of its arguments an instance of the container / scope / resolution context itself.
This allows using additional levels of indirection, as well as the use of information that uniquely identifies the context or scope. Additionally many provide hooks, like event handlers or the option to derive from a life cycle scope class, to interact with a scope being started or ended.
Principle
For AutoFac and your specific example, the following principle would work, using additional levels of indirection in registration.
// Inject `Data` instance resolved from current scope.
builder.Register<IMyService>(ctx => new MyService(ctx.Resolve<Data>()));
// Extra level of indirection, get a "factory" for a 'Data' instance.
builder.Register<Data>(ctx => ctx.Resolve<Func<Data>>()()).InstancePerLifetimeScope();
// The indirection resolves to a map of scopes to "factory" functions.
builder.Register<Func<Data>>(ScopedDataExtensions.GetFactory);
We can use any available unique property on a context / scope to construct this mapping.
// Maps scopes to data "factories".
public static class ScopedDataExtensions
{
private static readonly ConcurrentDictionary<object, Func<Data>> _factories = new ConcurrentDictionary<object, Fund<Data>>();
public static Func<Data> GetFactory(this IComponentContext ctx)
{
var factory = default(Func<Data>);
return _factories.TryGetValue(ctx.ComponentRegistry, out factory) ? factory : () => null;
}
public static void SetFactory(this ILifetimeScope scope, Func<Data> factory)
{
_factories[scope.ComponentRegistry] = factory;
}
}
We can use it like this to supply "local" data instances to be injected into our scoped service instances.
var myData = new Data("nested");
nestedScope.SetFactory(() => myData);
// ...
var myService = nestedScope.Resolve<IMyService>();
A more complete and generic example for AutoFac follows below.
Generic extension class for this pattern
public static class AutofacScopeExtensions
{
// Map from context => factories per type
public static readonly ConcurrentDictionary<object, ConcurrentDictionary<Type, object>> _factories =
new ConcurrentDictionary<object, ConcurrentDictionary<Type, object>>();
private static class ScopedFactoryFor<T>
{
public static Func<T> DefaultFactory = () => default(T);
public static Func<T> GetFactory(ConcurrentDictionary<Type, object> fromContext)
{
object factory;
return (fromContext.TryGetValue(typeof(T), out factory)) ? (Func<T>)factory : DefaultFactory;
}
}
public static IRegistrationBuilder<T, SimpleActivatorData, SingleRegistrationStyle>
WithContextFactoryFor<T>(this ContainerBuilder builder, Func<T> defaultFactory = null)
{
if (defaultFactory != null)
ScopedFactoryFor<T>.DefaultFactory = defaultFactory;
builder.Register<Func<T>>(AutofacScopeExtensions.GetFactory<T>);
return builder.Register<T>(ctx => ctx.Resolve<Func<T>>()());
}
public static IContainer BuildContainer(this ContainerBuilder builder)
{
var container = builder.Build();
container.ChildLifetimeScopeBeginning += OnScopeStarting;
return container;
}
public static ILifetimeScope SetScopeFactory<T>(this ILifetimeScope scope, Func<T> factory)
{
ScopeMapFor(scope)[typeof(T)] = factory;
return scope;
}
public static ILifetimeScope SetScopeValue<T>(this ILifetimeScope scope, T instance)
{
return SetScopeFactory(scope, () => instance);
}
public static Func<T> GetFactory<T>(IComponentContext ctx)
{
return ScopedFactoryFor<T>.GetFactory(ScopeMapFor(ctx));
}
private static ConcurrentDictionary<Type, object> ScopeMapFor(IComponentContext ctx)
{
return _factories.GetOrAdd(ctx.ComponentRegistry, x => new ConcurrentDictionary<Type, object>());
}
private static void OnScopeStarting(object sender, LifetimeScopeBeginningEventArgs evt)
{
evt.LifetimeScope.ChildLifetimeScopeBeginning += OnScopeStarting;
evt.LifetimeScope.CurrentScopeEnding += OnScopeEnding; // so we can do clean up.
}
private static void OnScopeEnding(object sender, LifetimeScopeEndingEventArgs evt)
{
var map = default(ConcurrentDictionary<Type, object>);
if (_factories.TryRemove(evt.LifetimeScope.ComponentRegistry, out map))
map.Clear();
}
}
Allowing the following syntax for registration:
builder.WithContextFactoryFor<Data>(() => new Data("Default")).InstancePerLifetimeScope();
builder.Register<IMyService>(ctx => new MyService(ctx.Resolve<Data>()));
And resolve like:
// ...
var myData = new Data("Some scope");
// ...
context.SetScopeFactory(() => myData);
// ...
// Will inject 'myData' instance.
var myService = context.Resolve<IMyService>();
Simpler Alternative
If you explicitly start nested scopes and at the time you do, you know how the scoped Data instance is to be created, you can skip the extension class and register the "factory" delegate with the nested scope when you create it:
var nestedScope = container.BeginLifetimeScope(
"L2",
x => x.RegisterInstance<Func<Data>>(() => new Data("nested")));
If I understand you correctly you want to use factories by delegating object creation to container while passing some parameters to its constructor.
This is implemented in Castle Windsor with typed factory facility.
Example classes we want to resolve:
public interface IMyService
{
void Do();
}
public class MyService : IMyService
{
private readonly Data _data;
private readonly IDependency _dependency;
public MyService(Data data, IDependency dependency)
{
_data = data;
_dependency = dependency;
}
public void Do()
{
throw new System.NotImplementedException();
}
}
public class Data
{
}
public interface IDependency
{
}
public class Dependency : IDependency
{
}
We create a factory interface:
public interface IMyServiceFactory
{
IMyService Create(Data data);
void Release(IMyService service);
}
We won't be implementing this interface because Castle Windsor will be generating an implementation with Dynamic Proxy. There's an important detail here: parameter name(data) in factory method and the one in the constructor should match.
Then we do the registration and try to resolve the values.
[Test]
public void ResolveByFactory()
{
WindsorContainer container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMyServiceFactory>().AsFactory());
container.Register(Component.For<IMyService>().ImplementedBy<MyService>().LifestyleScoped());
container.Register(Component.For<IDependency>().ImplementedBy<Dependency>().LifestyleScoped());
IMyServiceFactory factory = container.Resolve<IMyServiceFactory>();
IMyService myService1;
IMyService myService2;
using (container.BeginScope())
{
myService1 = factory.Create(new Data());
myService2 = factory.Create(new Data());
myService1.Should().BeSameAs(myService2);
}
using (container.BeginScope())
{
IMyService myService3 = factory.Create(new Data());
myService3.Should().NotBeSameAs(myService1);
myService3.Should().NotBeSameAs(myService2);
}
}
You will see that the object created in the same scope are the same references. Let me know if this is the behaviour you want.
Related
When creating an application with Dependency Injection and it utilizes a framework for Dependency Injection such as Unity (or Ninject).
How do you initialize registering the interfaces to the container at the beginning all together and keep them available for the application to use throughout its running lifecycle of the application?
Do you need to pass the DI Container to each method that may utilize dependency injection, or is there some way to make the container globally accessible so that you can register them all together in the beginning and access them throughout running the application without having to continually pass them, and be able to utilize them when ever needed?
Environment: Visual Studio 2015, C#, Microsoft Unity (for DI Container)
Example Code
static void Main(string[] args)
{
// Make Unity resolve the interface, providing an instance
// of TrivialPursuit class
var diContainer = new UnityContainer();
diContainer.RegisterType<IGame, TrivialPursuit>();
var gameInstance = diContainer.Resolve<IGame>();
var xotherClass = new AnotherClass();
xotherClass.TestOtherClassOtherMethod();
}
------ Another class without context of the Dependency Injection Class ------
public void TestOtherClassOtherMethod()
{
IGame gameInstance = -- -Container is Not available to resolve from in this class ---
}
Reason: I don't want to need to pass every possible type that I may need later on to each class I load up, I will just want to use the instances when I need them. The more deeper I get into classes, later as the application becomes more complex, I won't want to pass down instances for each type up from the Main() method to each class.
A Dependency Injection (DI) container is just that. A framework for facilitating DI. You don't pass the container around in order to resolve instances of objects. You just request the type you need in your classes constructor and the DI framework will inject the appropriate dependency.
Mark Seemann has written a good book on dependency injection that I would recommend.
You register everything that'll need to be resolved with the container in the composition root. That is to say when your program starts up is when everything should be registered.
Let's say we have the following code:
public class MyClass
{
public Run()
{
var dependency = new Dependency1();
dependency.DoSomething();
}
}
public class Dependency1
{
public void DoSomething()
{
var dependency = new Dependency2();
dependeny.DoSomethingElse();
}
}
public class Dependency2
{
public void DoSomethingElse()
{
}
}
This gives us the above dependency chain: MyClass -> Dependency1 -> Dependency2.
The first thing we should do is refactor the classes to take their dependencies through their constructor and rely on interfaces rather than concretions. We can't inject dependencies unless there is a place to inject them (constructor, property, etc).
Here is the refactored code:
public interface IMyClass
{
void Run();
}
public interface IDependency1
{
void DoSomething();
}
public interface IDependency2
{
void DoSomethingElse();
}
public class MyClass : IMyClass
{
public readonly IDependency1 dep;
public MyClass(IDependency1 dep)
{
this.dep = dep;
}
public void Run()
{
this.dep.DoSomething();
}
}
public class Dependency1 : IDependency1
{
public readonly IDependency2 dep;
public MyClass(IDependency2 dep)
{
this.dep = dep;
}
public void DoSomething()
{
this.dep.DoSomethingElse();
}
}
public class Dependency2 : IDependency2
{
public void DoSomethingElse()
{
}
}
You'll notice the classes now all take their dependencies through their constructors and do not new up anything. Classes should only take in dependencies that they actually need. For example, MyClass does not NEED a Dependency2 so it doesn't ask for one. It only asks for a Dependency1 because that's all it needs. Dependency1 NEEDS Dependency2, not MyClass.
Now to wire it all up WITHOUT a container we would just new it all up in the composition root:
void Main()
{
var myClass = new MyClass(new Dependency1(new Dependency2()));
}
You can see how that could get cumbersom if we had tons of classes and depdencies. That's why we use a container. It handles all the depdency graph for us. With a container we'd rewrite it as follows:
void Main()
{
// the order of our registration does not matter.
var container = new Container();
container.Register<IDependency1>.For<Dependency1>();
container.Register<IDependency2>.For<Dependency2>();
container.Register<IMyClass>.For<MyClass>();
// then we request our first object like in the first example (MyClass);
var myClass = container.Resolve<IMyClass>();
myClass.Run();
}
In the second example the container will handle wiring up all the dependencies. So we never need to pass Depedency2 to MyClass and then to Depedency1. We only need to request it in Dependency1 and the container will wire it up for us like in the first example.
So in your example we would rewrite it like so:
static void Main(string[] args)
{
var game = new UnityContainer();
game.RegisterType<IGame, TrivialPursuit>();
game.RegisterType<IAnotherClass, AnotherClass>();
game.RegisterType<IYetAnotherClass, YetAnotherClass>();
var gameInstance = game.Resolve<IGame>();
// you'll need to perform some action on gameInstance now, like gameInstance.RunGame() or whatever.
}
public class Game : IGame
{
public Game(IAnotherClass anotherClass)
{
}
}
public class AnotherClass : IAnotherClass
{
public AnotherClass(IYetAnotherClass yetAnotherClass)
{
}
}
public class YetAnotherClass : IYetAnotherClass {}
In these cases there is no need to pass the container around. You register your dependencies with the container then request them in your classes constructors. If you wish to use the container in the class WITHOUT requesting it through the constructor then you are not doing DI you are just using the container as a singleton service locator. Something that should generally be avoided.
Container as a Service Locator
This should be generally avoided but if you want to use the container as a service locator you have two options:
1) Pass the container into your classes that need it through the constructor.
You can use the above examples for wiring your classes up for DI. But instead of requesting a dependency like IDependency in the constructor you just pass the container.
public class Game : IGame
{
public Game(IContainer container)
{
var blah = container.Resolve<IBlah>();
}
}
2) Request your container through a static class:
public static class ServiceLocator
{
private static IContainer container;
public static IContainer Container
{
get
{
if (container == null)
{
container = new Container();
}
return container;
}
}
}
Register everything as normal in your composition root using the ServiceLocator class. Then to use:
public class MyClass
{
public void DoSomething()
{
var blah = ServiceLocator.Container.Resolve<IBlah>();
}
}
Can we inject dependency as method parameter instead of constructor parameter either using MEF or Autofac?
Thanks
I don't know about MEF, as I've never used it. You can do it with Unity and with Autofac
Unity
From the MSFT documentation.
Unity instantiates dependent objects defined in parameters of methods that carry the InjectionMethod attribute within the scope of the target object. Then it calls the attributed method of the target object before returning the object to the caller. You must apply the InjectionMethod attribute in the target class to initiate method call injection.
public class MyObject
{
public SomeOtherObject dependentObject;
[InjectionMethod]
public void Initialize(SomeOtherObject dep)
{
// assign the dependent object to a class-level variable
dependentObject = dep;
}
}
That will mark the class as having a dependency method that must get invoked when the class is instanced, and have its method parameter injected.
IUnityContainer uContainer = new UnityContainer();
MyObject myInstance = uContainer.Resolve<MyObject>();
// access the dependent object
myInstance.dependentObject.SomeProperty = "Some value";
Autofac
Autofac does it through lambdas or callbacks during the activation of a service. From the Autofac documentation
While constructor parameter injection is the preferred method of passing values to a component being constructed, you can also use property or method injection to provide values.
Property injection uses writeable properties rather than constructor parameters to perform injection. Method injection sets dependencies by calling a method.
// Register the type that you want to resolve with a resolution callback. Within the callback, invoke the method with a resolved dependency.
builder.Register(c => {
var result = new MyObjectType();
var dep = c.Resolve<TheDependency>();
result.SetTheDependency(dep);
return result;
});
An alternative is the registration callback.
builder
.Register<MyObjectType>()
.OnActivating(e => {
var dep = e.Context.Resolve<TheDependency>();
e.Instance.SetTheDependency(dep);
});
Both frameworks can only do the method injection at the time of resolution. However, you can't inject a dependency in to a method after the object has been instanced. In those scenarios, you should use a factory to fetch the dependency you have, having the factory resolve it through your DI container.
Factory
// Create the factory. The factory will have a static method that the DI system can register a lambda with, so that the factory can resolve through the DI container without being tightly coupled to it.
public class BarFactory
{
private static Func<IBarDependency> internalFactory;
public static void SetFactory(Func<IBarDependency> factory)
{
this.internalFactory = factory;
}
public IBarDependency CreateBar()
{
// Use the DI container lambda assigned in SetFactory to resolve the dependency.
return internalFactory();
}
}
public class DependencyInjectionBootstrap
{
IContainer container;
public void SetupDI()
{
var builder = new ContainerBuilder();
builder.RegisterType<BarDependency>().As<IBarDependency>();
container = builder.Build();
// Tell the factory to resolve all IBarDependencies through our IContainer.
BarFactory.SetFactory(() => container.Resolve<IBarDependency>());
}
}
public class FooViewModel
{
public void ExecuteSave()
{
var barFactory = new BarFactory();
IBarDependency bar = barFactory.CreateBar();
}
}
I think I get most things about dependency inversion and using an IoC container, but one thing still does not appear clear to me. How do I use autofac to automate the following factory:
public class WidgetFactory
{
public static IWidget Create(int foo, double bar)
{
return new Widget(foo, bar);
}
}
public class Widget
{
private readonly int foo;
private readonly double bar;
public Widget(int foo, double bar)
{
this.foo = foo;
this.bar = bar;
}
}
elsewhere...
public class FoobarUser
{
public void Method()
{
var widget = WidgetFactory.Create(3, 4.863);
// Do something with my widget
// Possibly add it to a widget collection
}
}
Basically, I need thousands of widgets to be created and I'm not sure of the best way of doing so. How would I create the widget factory using autofac and how would I use that in Method, bearing in mind that Method does not contain a reference to the IContainer?
The way to fix this problem is the following:
Change WidgetFactory to define a delegate for creating widgets:
public class WidgetFactory
{
public delegate IWidget Create(int firstParam, double secondParam);
}
In your autofac module, wire up the factory using the RegisterGeneratedFactory method. This will automatically create your factory for you:
public class TestClassModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<Widget>().As<IWidget>();
builder.RegisterGeneratedFactory<WidgetFactory.Create>(new TypedService(typeof(IWidget)));
builder.RegisterType<FoobarUser>();
}
}
Inject the factory into FoobarUser:
public class FoobarUser
{
private readonly WidgetFactory.Create factory;
public FoobarUser(WidgetFactory.Create factory)
{
this.factory = factory;
}
public void Method()
{
var widget = this.factory(3, 4.836);
// Do something with my widget
// Possibly add it to a widget collection
}
}
There are basically two ways to handle parameters:
At registration time - you can provide them in lambda registrations (Register(c => T)) or you can append parameters to reflection-based (RegisterType<T>) registrations.
At resolve time - you can either append parameters to Resolve<T>() calls or you can use delegate factories or Func<T> dependencies to dynamically create a factory method that can be used by your component.
There is robust documentation on all of these options with examples over at the Autofac documentation site:
Parameters at registration time
Parameters at resolve time
You would inject dependencies into your factory with an IoC container using constructor or property injection, not args into a method. If you needed to inject specific values as parameters into your service's constructor, you could set that up during registration similar to the below code.
Here, I'm getting a XML file path from my web.config and passing that value into my repository's constructor:
var builder = new ContainerBuilder();
var xmlFileName = HttpContext.Current.Server.MapPath(
ConfigurationManager.AppSettings["xmlData"]);
builder.Register(c => new XmlAdvertisementRepository(new XmlContext(xmlFileName)))
.AsImplementedInterfaces()
.InstancePerHttpRequest();
I've been experiencing some strange code-issues, and finally seem to have noticed that what as supposed to be acting as Singleton, is not actually a singleton. This is a cache-class, so I am ending up having multiple-versions of the same cache. I've written some test-code as per below, and in my eyes this should work. Am I doing anything wrong, or have I stumbled upon a bug?
public class GenericClassesNotRegisteredAsSingletonTest
{
public interface ICacheManager<T> { }
public class SettingsData { }
public class SettingsCache : CacheManager<SettingsData> { }
public class CacheManager<T> : ICacheManager<T> { }
[Test]
public void Test()
{
var container = new Container();
var registration = Lifestyle.Singleton
.CreateRegistration(typeof(SettingsCache),
typeof(SettingsCache), container);
container.AddRegistration(
typeof(ICacheManager<SettingsData>), registration);
container.Verify();
var cache1 = container.GetInstance<SettingsCache>();
var cache2 = container.GetInstance<SettingsCache>();
bool sameRef = cache1 == cache2;
Assert.That(sameRef == true);
}
}
You made the following registration:
_container.AddRegistration(
serviceType: typeof(ICacheManager<SettingsData>),
registration: registration);
And you're doing the following resolve:
_container.GetInstance<SettingsCache>();
You haven't registered SettingsCache explicitly, but only ICacheManager<SettingsData>. Since SettingsCache is a concrete class, Simple Injector will resolve it as transient instance for you.
The solution is to either register SettingsCache explicitly or resolve ICacheManager<SettingsData> instead. You can make a second registration with using the same Registration instance. For instance:
_container.AddRegistration(
serviceType: typeof(SettingsCache),
registration: registration);
The Diagnostic Services will warn you about this this type of misconfiguration.
I have two scopes, one nested inside the other. When I resolve a particular service, I would like one component to be resolved in one root scope and a different one in the child scope. Is there an easy way of doing this?
I have managed to get something working using a factory class that determines what the current scope is and then returning the appropriate instance:
IContainer BuildContainer()
{
var builder = new ContainerBuilder();
// ...
builder.RegisterType<FooInParentScope>().AsSelf();
builder.RegisterType<FooInChildScope>().AsSelf();
builder.RegisterType<FooFactory>().AsImplementedInterfaces();
builder.Register<IFoo>(c => c.Resolve<IFooFactory>().GetFoo()).InstancePerLifetimeScope();
// ...
}
class FooFactory : IFooFactory
{
private readonly ILifetimeScope m_scope;
public FooFactory(ILifetimeScope scope)
{
m_scope = scope;
}
public IFoo GetFoo()
{
if (m_scope.Tag == "ParentScope")
return m_scope.Resolve<FooInParentScope>();
else
return m_scope.Resolve<FooInChildScope>();
}
}
class FooInParentScope : IFoo
{
}
class FooInChildScope : IFoo
{
}
There are a number of issues with this approach:
I have to add an extra class (or 2 - not sure if the IFooFactory is really necessary)
The code above does not cope with other scopes that are nested in ParentScope. I can fix this by casting the scope to Autofac.Core.Lifetime.LifetimeScope and examining the ParentLifetimeScope property, but that is probably not a particularly safe thing to do.
You may register FooInParentScope in root container as SingleInstance. And when creating inner lifetimescope add registration for FooInChildScope as SingleInstance (override registration).
builder.RegisterType<FooInParentScope>().As<IFoo>.SingleInstance();
var container = builder.Build();
var childScope = container.BeginLifetimeScope(innerBuilder =>
{
// override registration for IFoo in child lifetime scope:
innerBuilder.RegisterType<FooInChildScope>().As<IFoo>().SingleInstance();
});
FooInParentScope fooInParentScope = (FooInParentScope) container.Resolve<IFoo>();
FooInChildScope fooInChildScope = (FooInChildScope) childScope.Resolve<IFoo>();