Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Bo Jacobsen 324 posts 1439 karma points
    1 week ago
    Bo Jacobsen
    0

    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>();
        }
    }
    
  • Bo Jacobsen 324 posts 1439 karma points
    1 week ago
    Bo Jacobsen
    0

    I dunno why it is always putting it under Using Umbraco And Getting Started

  • Bo Jacobsen 324 posts 1439 karma points
    1 week ago
    Bo Jacobsen
    100

    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);
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft