Get class type during dependency resoluton - c#

When registering a type for my unity container, I need to pass in the calling class's type into the constructor of the resolved object.
This is the class where I am injecting some interfaces into the constructor.
namespace MyNamespace
{
internal class ProcessingService: IProcessingService
{
private readonly ISomeClass1 someClass1;
private readonly ISomeClass2 someClass2;
public ProcessingService(ISomeClass1 someClass1, ISomeClass2 someClass2)
{
this.someClass1 = someClass1;
this.someClass2 = someClass2;
}
}
}
SomeClass2 expects Type in the constructor:
public class SomeClass2
{
public SomeClass2(Type type)
{
//...
}
}
Here is my unity bootstrap class where I set up my container. Now, for ISomeClass2, when it resolves to SomeClass2, it needs to pass in the type of ProcessingService.
namespace MyNamespace
{
public class UnityBootstrap : IUnityBootstrap
{
public IUnityContainer Configure(IUnityContainer container)
{
return container
.RegisterType<ISomeClass1, SomeClass1>()
.RegisterType<ISomeClass2>(new InjectionFactory(fac =>
{
// IMethodBase.GetCurrentMethod().DeclaringType is returning MyNamespace.UnityBootstrap
// whereas I need to get MyNamespace.ProcessingService
return new SomeClass2(MethodBase.GetCurrentMethod().DeclaringType);
}));
}
}
}
Is there a way to do this using the InjectionFactory (or some other way within my Configure method)?

If you have control over the ProcessingService, you could create a generic wrapper around SomeClass2 and then register it using open generics. But that would require you modify the constructor of the ProcessingService.
public interface IGenericSomeClass2<T>: ISomeClass2 {}
public class GenericSomeClass2<T>: IGenericSomeClass2<T>
{
private readonly ISomeClass2 someClass2;
public GenericSomeClass2()
{
this.someClass2 = new SomeClass2(typeof(T));
}
// Pass-through implementation
}
public IUnityContainer Configure(IUnityContainer container)
{
return container
.RegisterType<ISomeClass1, SomeClass1>()
.RegisterType(typeof(IGenericSomeClass2<>), typeof(GenericSomeClass2<>));
}
internal class ProcessingService: IProcessingService
{
private readonly ISomeClass1 someClass1;
private readonly ISomeClass2 someClass2;
public ProcessingService(ISomeClass1 someClass1, IGenericSomeClass2<ProcessingService> someClass2)
{
this.someClass1 = someClass1;
this.someClass2 = someClass2;
}
}

IMHO, there are two points of view to this problem:
1) If SomeClass2 will always use the type ProcessingService then you can pass the type argument directly into the InjectionFactory
container.RegisterType<ISomeClass2>(new InjectionFactory(_ =>
{
return new SomeClass2(typeof(ProcessingService));
}));
2) Otherwise, if the type argument differs throughout application you should consider adding a registration method to interface ISomeClass2 and register the type from within the constructor to emphasize the dependency/variation.
public interface ISomeClass2
{
void DoSomething();
void RegisterProcessingServiceType(Type processingServiceType);
}
public class SomeClass2 : ISomeClass2
{
private Type _type;
public void DoSomething()
{
if(_type == null)
throw InvalidOperationException("Register processing service type before doing stuff.");
// actually do something
}
public void RegisterProcessingServiceType(Type serviceType)
{
_type = serviceType;
}
}
internal class ProcessingService: IProcessingService
{
private readonly ISomeClass1 someClass1;
private readonly ISomeClass2 someClass2;
public ProcessingService(ISomeClass1 someClass1, ISomeClass2 someClass2)
{
this.someClass1 = someClass1;
this.someClass2 = someClass2;
this.someClass2.RegisterProcessingServiceType(this.GetType());
}
}

If you do not control ProcessingService (or other consumers of SomeClass2), you could customize the registration of those consumers. This method is a bit more intrusive because you would have to create an injection factory for every consumer.
container
.RegisterType<IProcessingService, ProcessingService>(new InjectionFactory((c, type, name) =>
{
return new ProcessingService(c.Resolve<ISomeClass1>(), new SomeClass2(type));
}));

Related

Can you have generic create method for Zenject

So I have a base class and some derived classes, I want to have just one factory with generic create method witch will create appropriate instances and inject all dependencies. Is this possible using Zenject?
Something like.
factory.Create<Archer>()
For now I am doing this but as you see this is not very clean solution.
public class CustomFactory : IFactory<Type, BaseUnit>
{
private DiContainer _container;
public CustomFactory(DiContainer container)
{
_container = container;
}
public BaseUnit Create<Type>()
{
return null;
}
public BaseUnit Create(Type type)
{
if (type.BaseType != typeof(BaseUnit))
{
Debug.LogError("you cant create objects that are not derrived from base unit");
return null;
}
object obj = _container.Resolve(type) ;
return _container.InstantiatePrefabForComponent(type, obj as UnityEngine.Object, null, new object[0]) as BaseUnit;
}
}
I think the way you have it is probably the easiest way to do this. Here's some minor changes to what you did:
public class UnitFactory
{
readonly DiContainer _container;
readonly List<UnityEngine.Object> _prefabs;
public UnitFactory(
List<UnityEngine.Object> prefabs,
DiContainer container)
{
_container = container;
_prefabs = prefabs;
}
public BaseUnit Create<T>()
where T : BaseUnit
{
var prefab = _prefabs.OfType<T>().Single();
return _container.InstantiatePrefabForComponent<T>(prefab);
}
}
public class TestInstaller : MonoInstaller<TestInstaller>
{
public FooUnit FooPrefab;
public BarUnit BarPrefab;
public override void InstallBindings()
{
Container.Bind<UnitFactory>().AsSingle();
Container.Bind<UnityEngine.Object>().FromInstance(FooPrefab).WhenInjectedInto<UnitFactory>();
Container.Bind<UnityEngine.Object>().FromInstance(BarPrefab).WhenInjectedInto<UnitFactory>();
}
}
Only drawback with this approach is that the prefabs will not be validated, so if they have missing injections it won't be caught until runtime. The alternative would be to create individual factories for each BaseUnit, and then inject those factories into UnitFactory, but that would probably get messy

Retrieve instantiated types from UnityContainer

(Using Unity 4.0.1)
Given a UnityContainer object, is there any way to retrieve all the objects that have been instantiated by the container up to that point in time? E.g. something like
IEnumerable<object> instantiatedObjects = unityContainer.GetAllInstantiatedObjects();
or, even better, filtering according to those that derive from a given type:
IEnumerable<IFoo> instantiatedFoos = unityContainer.GetAllInstantiatedObjects<IFoo>();
Following RB's suggestion, the following approach implements a custom Unity extension with a strategy that keeps a reference to each instantiated object upon PostInitializtion.
N.B. The following code is for illustration only, and is not intended to be thread-safe/exception-safe etc.
First, the implementation of the Extension class and other classes it relies on.
public class ObjectContainer
{
private readonly List<object> _instantiatedObjects = new List<object>();
public void Add(object instantiatedObject)
{
_instantiatedObjects.Add(instantiatedObject);
}
public IEnumerable<object> GetInstantiatedObjects()
{
return _instantiatedObjects;
}
public IEnumerable<T> GetInstantiatedObjects<T>()
{
return GetInstantiatedObjects().OfType<T>();
}
}
public class InstantiatedObjectsStrategy : BuilderStrategy
{
private readonly ObjectContainer _objectContainer;
public InstantiatedObjectsStrategy(ObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
public override void PostBuildUp(IBuilderContext context)
{
_objectContainer.Add(context.Existing);
}
}
public class InstantiatedObjectsExtension : UnityContainerExtension
{
private readonly ObjectContainer _objectContainer = new ObjectContainer();
protected override void Initialize()
{
Context.Container.RegisterInstance(_objectContainer);
Context.Strategies.Add(new InstantiatedObjectsStrategy(_objectContainer),
UnityBuildStage.PostInitialization);
}
}
The extension can be added to the UnityContainer immediately after creation:
IUnityContainer container = new UnityContainer();
container.AddNewExtension<InstantiatedObjectsExtension>();
The instantiated objects can then be retrieved from the container at a later stage as follows:
IEnumerable<object> instantiatedObjects = container.Resolve<ObjectContainer>().GetInstantiatedObjects();
IEnumerable<Foo> instantiatedFoos = container.Resolve<ObjectContainer>().GetInstantiatedObjects<Foo>();

How implement Strategy/Facade Pattern using Unity Dependecy Injection Web API

How tell to Unity.WebApi dependency injection framework, inject the correct class in the correct controller?
DI Project Container
public class UnityContainerConfig
{
private static IUnityContainer _unityContainer = null;
public static IUnityContainer Initialize()
{
if (_unityContainer == null)
{
_unityContainer = new Microsoft.Practices.Unity.UnityContainer()
.RegisterType<IMyInterface, MyClass1>("MyClass1")
.RegisterType<IMyInterface, MyClass2>("MyClass2")
}
}
-MVC PROJECT-
public static class UnityConfig
{
public static void RegisterComponents()
{
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(DependencyInjection.UnityContainer.UnityContainerConfig.Initialize());
}
}
Controller 1:
private IMyInterface _myInterface
///MyClass1
public XController(
IMyInterface myInterface
)
{
_myInterface = myInterface
}
Controller 2:
private IMyInterface _myInterface
///MyClass2
public YController(
IMyInterface myInterface
)
{
_myInterface = myInterface
}
Rather than using a strategy or facade to solve this, a better solution would be to redesign your interfaces to be unique per controller. Once you have a unique interface type, your DI container will automatically inject the right service into each controller.
Option 1
Use a generic interface.
public interface IMyInterface<T>
{
}
public class XController
{
private readonly IMyInterface<XClass> myInterface;
public XController(IMyInterface<XClass> myInterface)
{
this.myInterface = myInterface;
}
}
public class YController
{
private readonly IMyInterface<YClass> myInterface;
public YController(IMyInterface<YClass> myInterface)
{
this.myInterface = myInterface;
}
}
Option 2
Use interface inheritance.
public interface IMyInterface
{
}
public interface IXMyInterface : IMyInterface
{
}
public interface IYMyInterface : IMyInterface
{
}
public class XController
{
private readonly IXMyInterface myInterface;
public XController(IXMyInterface myInterface)
{
this.myInterface = myInterface;
}
}
public class YController
{
private readonly IYMyInterface myInterface;
public YController(IYMyInterface myInterface)
{
this.myInterface = myInterface;
}
}

How to specify a child scope for constructor func factory parameter?

I want to do something like:
class MyClass
{
Func<OtherClass> _factory;
public MyClass([WithChildScope("OtherClassScope")] Func<OtherClass> other)
{
_factory = other;
}
public OtherClass LoadOther(int id)
{
var entity = DbHelper.LoadEntity(id);
var other = _factory();
other.Configure(entity);
return other;
}
}
So that each call to LoadOther should create a new OtherClass instance with its own scope (inside a parent scope in which MyClass was constructed). But there is no [WithChildScope] attribute.
In NInject I would use DefinesNamedScope with ContextPreservation.
Can I do it in AutoFac without passing locator everywhere?
So I found the solution myself:
k.RegisterType<Scoped<UserScope>>().AsSelf().WithParameter("childTag", "User");
public class Scoped<T>
{
public Scoped(ILifetimeScope scope, object childTag)
{
Value = scope.BeginLifetimeScope(childTag).Resolve<T>();
}
public T Value { get; }
}
public class UserRepository
{
Func<Scoped<UserScope>> _factory;
public UserRepository(Func<Scoped<UserScope>> factory)
{
_factory = factory;
}
}

NSubstitute and Unity

I am currently trying to learn DI & Mocking, with Unity and NSubstitute. I am also using an automocking extension taken from this question: Is this possible with Unity (Instead of Castle Windsor)?
In my unit test below I am trying to set an NSubstitute return value of 10 from my method Add(). However when debugging through the controller call the assigned value is the default 0 rather than the expected 10. The proxy does not seem to be intercepting the method call.
I suspect this is caused by not registering my Types/container correctly, anybody able to point me in the right direction?
[TestFixture]
public class ApplicationControllerTests
{
private IUnityContainer _container;
private ApplicationController _controller;
private ISampleService _sampleService;
[SetUp]
public void SetUp()
{
_container = new UnityContainer().AddExtension(new AutoMockingContainerExtension());
_controller = _container.Resolve<ApplicationController>();
_sampleService = _container.Resolve<ISampleService>();
}
[Test]
public void TestSampleService()
{
// This line is not working
_sampleService.Add(Arg.Any<int>(), Arg.Any<int>()).Returns(10);
var result = _controller.Index();
_sampleService.Received().Add(Arg.Any<int>(), Arg.Any<int>());
}
}
public class AutoMockingContainerExtension : UnityContainerExtension
{
protected override void Initialize()
{
var strategy = new AutoMockingBuilderStrategy(Container);
Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
}
class AutoMockingBuilderStrategy : BuilderStrategy
{
private readonly IUnityContainer _container;
public AutoMockingBuilderStrategy(IUnityContainer container)
{
_container = container;
}
public override void PreBuildUp(IBuilderContext context)
{
var key = context.OriginalBuildKey;
if (key.Type.IsInterface && !_container.IsRegistered(key.Type))
context.Existing = CreateSubstitute(key.Type);
}
private static object CreateSubstitute(Type type)
{
return Substitute.For(new[] { type }, null);
}
}
}
And my controller code
public class ApplicationController : BaseController
{
private readonly ISampleService _sampleService;
public ApplicationController(ISampleService sampleService)
{
_sampleService = sampleService;
}
public ActionResult Index()
{
var result = _sampleService.Add(2, 3);
// result is 0, expected 10 ??
return View();
}
}
public interface ISampleService
{
int Add(int first, int second);
}
public class SampleService : ISampleService
{
public int Add(int first, int second)
{
return first + second;
}
}
Actually Tormod is right the problem is that the AutoMockingBuilderStrategy returns a different mock instance every time when somebody requests an ISampleService form the container.
So there is a bug in my original implementation namely the AutoMockingBuilderStrategy doesn't store the created mocks:
Here is a fixed version:
public class AutoMockingContainerExtension : UnityContainerExtension
{
protected override void Initialize()
{
var strategy = new AutoMockingBuilderStrategy(Container);
Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
}
class AutoMockingBuilderStrategy : BuilderStrategy
{
private readonly IUnityContainer container;
private readonly Dictionary<Type, object> substitutes
= new Dictionary<Type, object>();
public AutoMockingBuilderStrategy(IUnityContainer container)
{
this.container = container;
}
public override void PreBuildUp(IBuilderContext context)
{
var key = context.OriginalBuildKey;
if (key.Type.IsInterface && !container.IsRegistered(key.Type))
{
context.Existing = GetOrCreateSubstitute(key.Type);
context.BuildComplete = true;
}
}
private object GetOrCreateSubstitute(Type type)
{
if (substitutes.ContainsKey(type))
return substitutes[type];
var substitute = Substitute.For(new[] {type}, null);
substitutes.Add(type, substitute);
return substitute;
}
}
}
I suspect that you are dealing with two different instances of ISampleService, created in lines 2 and 3 of Setup, respectively.
Could you, for test, make the _sampleServie field public and in the third Setup() line try
_sampleService = _controller._sampleService;

Categories