Dependency Injection on Activator Createinstance Reflection
Hi all.
I am trying to reflect all classes of a specific interface and run a method. This works until i try to use services into the class constructor, like the IScopeProvider.
So i need to be able to get my Activator.CreateInstance(type) to pick up all paramaters in the constructor with Dependency Injection.
Does anyone know what to do?
This is what i have:
My interface to find
public interface IFindMe
{
string Name { get; }
void PerformRun();
}
Class to reflect
public class TestJob : IFindMe
{
private readonly IScopeProvider _scopeProvider;
public TestJob(IScopeProvider scopeProvider)
{
_scopeProvider = scopeProvider;
}
public string Name => "Find me ffs";
public void PerformRunAsync()
{
using (var scope = _scopeProvider.CreateScope(autoComplete: true))
{
// Just to try something
var instanceId = scope.InstanceId;
}
}
}
IComponent, where all the interfaces are picked up
public class FindMeComponent : IComponent
{
private readonly ILogger _logger;
public FindMeComponent(ILogger logger)
{
// When it works i wanna log things :)
_logger = logger;
}
public void Initialize()
{
var listOfTypes = new List<Type>();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
try
{
var foundTypes = assembly.GetTypes();
listOfTypes.AddRange(foundTypes);
}
catch (ReflectionTypeLoadException e)
{
var exceptionTypes = e.Types.Where(t => t != null);
listOfTypes.AddRange(exceptionTypes);
}
}
var type = typeof(IFindMe);
var types = listOfTypes.Where(t => type.IsAssignableFrom(t) && !t.IsInterface);
foreach (var type in types)
{
// This works until i use a class that has parameters in the contructor.
object calcInstance = Activator.CreateInstance(type);
var name = (string)type.GetProperty("Name").GetValue(calcInstance, null);
var methodInfo = _type.GetMethod("PerformRun");
methodInfo.Invoke(_calcInstance, null);
}
}
public void Terminate()
{
}
}
IUserComposer, where i register the FindMeComponent
public class Installer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Components().Append<FindMeComponent>();
}
}
I got it to work. I dunno if its the best solution, but its the only one i can come around.
So basically you have to make sure there is only one constructor. And that constructor either have to be parameterless or only contain of Dependency Injection services. And from what i could search me to, its called Bastard Injection DI anti-pattern.
Then you need to find out if the constructor have parameters or not. If the constructor have parameters, you find each parameter and get the instance of its type Umbraco.Web.Composing.Current.Factory.GetInstance and then you pass the instances as an object array into the Activator.CreateInstance
public void Initialize()
{
var listOfTypes = new List<Type>();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
try
{
var foundTypes = assembly.GetTypes();
listOfTypes.AddRange(foundTypes);
}
catch (ReflectionTypeLoadException e)
{
var exceptionTypes = e.Types.Where(t => t != null);
listOfTypes.AddRange(exceptionTypes);
}
}
var typeOfInterface = typeof(IFindMe);
var types = listOfTypes.Where(t => typeOfInterface.IsAssignableFrom(t) && !t.IsInterface);
foreach (var type in types)
{
object calcInstance = null;
var constructors = type.GetConstructors();
var firstConstrutor = constructors.FirstOrDefault(); // Bastard Injection DI anti-pattern
if (firstConstrutor != null)
{
var constructorParameters = firstConstrutor.GetParameters();
if (constructorParameters != null && constructorParameters.Any())
{
var objectList = new List<object>();
foreach (var constructorParameter in constructorParameters)
{
var cpType = constructorParameter.ParameterType;
var instance = Umbraco.Web.Composing.Current.Factory.GetInstance(cpType);
objectList.Add(instance);
}
calcInstance = Activator.CreateInstance(type, objectList.ToArray());
}
}
if (calcInstance == null)
{
calcInstance = Activator.CreateInstance(type);
}
var name = (string)type.GetProperty("Name").GetValue(calcInstance, null);
var methodInfo = type.GetMethod("PerformRun");
methodInfo.Invoke(calcInstance, null);
}
}
Old post, but thought I would update this for Umbraco 9 in case anyone else wants to do this. You can use the following instead of Activator.CreateInstance()
Dependency Injection on Activator Createinstance Reflection
Hi all.
I am trying to reflect all classes of a specific interface and run a method. This works until i try to use services into the class constructor, like the IScopeProvider.
So i need to be able to get my
Activator.CreateInstance(type)
to pick up all paramaters in the constructor with Dependency Injection.Does anyone know what to do?
This is what i have:
My interface to find
Class to reflect
IComponent, where all the interfaces are picked up
IUserComposer, where i register the FindMeComponent
I dunno why it is always putting it under
Using Umbraco And Getting Started
this has been driving me nuts for months now! makes finding anything a real challenge...
I got it to work. I dunno if its the best solution, but its the only one i can come around.
So basically you have to make sure there is only one constructor. And that constructor either have to be parameterless or only contain of Dependency Injection services. And from what i could search me to, its called Bastard Injection DI anti-pattern.
Then you need to find out if the constructor have parameters or not. If the constructor have parameters, you find each parameter and get the instance of its type
Umbraco.Web.Composing.Current.Factory.GetInstance
and then you pass the instances as an object array into theActivator.CreateInstance
Old post, but thought I would update this for Umbraco 9 in case anyone else wants to do this. You can use the following instead of Activator.CreateInstance()
The service provider can be obtained via Dependency Injection in the constructor of your class. i.e.
lee, can't thank you enough for posting this!
i have a service class i've been using in virtually every umbraco 8 project i've worked on in the last 3 years...
one of the methods looked like this:
which quickly blew up when i dropped it into the umbraco 9 project i've been working on!
but you're post helped me convert it to this:
and i'm back in business!
is working on a reply...