15

I'm using an IServiceCollection to create a list of required services for my objects. Now I want to instantiate an object and have the DI container resolve the dependencies for that object

Example

// In my services config.
services
    .AddTransient<IMyService, MyServiceImpl>();

// the object I want to create.
class SomeObject
{
    public SomeObject(IMyService service)
    {
        ...
    }
}

How to I get the DI container to create an object of type SomeObject, with the dependecies injected? (presumably this is what it does for controllers?)

Note: I do not want to store SomeObject in the services collection, I just want to be able to do something like this...

SomeObject obj = startup.ServiceProvider.Resolve<SomeObject>();

... Rationale: I don't have to add all of my controllers to the service container, so I don't see why I would have to add SomeObject to it either!?

radarbob
  • 4,964
  • 2
  • 23
  • 36
Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
  • Where/how you you want to create the object? – Nkosi Oct 30 '16 at 22:37
  • @Nkosi In the Main method of a console app...something like SomeObject x = startup.ServiceProvider.ResolveDependenciesFor(); – Matthew Layton Oct 30 '16 at 22:39
  • Relevant question: http://stackoverflow.com/questions/31863981/how-to-resolve-instance-inside-configureservices-in-asp-net-core – apk Oct 30 '16 at 22:41
  • relevant article: https://msdn.microsoft.com/en-us/magazine/mt707534.aspx – Nkosi Oct 30 '16 at 22:42
  • Use a service provider – Nkosi Oct 30 '16 at 22:42
  • In order to resolve an object, the service collection needs to be aware of how to resolve it. – Nkosi Oct 30 '16 at 22:44
  • @Nkosi how does it know how to resolve any controller when I don't explicitly add them? – Matthew Layton Oct 30 '16 at 22:45
  • 1
    `Rationale: I don't have to add all of my controllers to the service container, so I don't see why I would have to add SomeObject to it either` The framework is doing that for you. it is using a convention and registers all controllers for you – Nkosi Oct 30 '16 at 22:46
  • You can create somethign like that yourself. eg. a custom attribute or interface that tags your custom classes and create an extension method that uses reflection to search for your classes and add them to the service collection. – Nkosi Oct 30 '16 at 22:48

3 Answers3

21

As stated in the comments to the marked answer, you can use ActivatorUtilities.CreateInstance method. This functionality already exists in .NET Core (since version 1.0, I believe).

See: https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.activatorutilities.createinstance

kiripk
  • 276
  • 5
  • 5
6

It's a little rough, but this works

public static class ServiceProviderExtensions
    {
        public static TResult CreateInstance<TResult>(this IServiceProvider provider) where TResult : class
        {
            ConstructorInfo constructor = typeof(TResult).GetConstructors()[0];

            if(constructor != null)
            {
                object[] args = constructor
                    .GetParameters()
                    .Select(o => o.ParameterType)
                    .Select(o => provider.GetService(o))
                    .ToArray();

                return Activator.CreateInstance(typeof(TResult), args) as TResult;
            }

            return null;
        }
    }
Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
  • How is this using the `IServiceProvider` to instantiate the object (with all dependencies injected)? – Alex Wiese Oct 30 '16 at 23:27
  • @alexw .Select(o => provider.GetService(o)) – Matthew Layton Oct 30 '16 at 23:28
  • @alexw basic principle, provided there is one constructor, iterate over it's parameter types, resovle them using the service provider and then create an instance using the results. – Matthew Layton Oct 30 '16 at 23:29
  • Uhh, shouldn't functionality like this already exist in the base framework? I don't want to be reinventing the wheel with this. – flodin Sep 29 '17 at 08:57
  • 2
    @flodin It's been a long time since I wrote this, but yes I think this functionality does already exist. The DI stuff baked into .NET Core implements the Service Locator pattern. This should lead you in the right direction... https://joonasw.net/view/aspnet-core-di-deep-dive – Matthew Layton Sep 29 '17 at 09:38
  • I have sent 30 minutes to find again this answer to vote it up. Tnx. This solved my problem with DI and Activator.CreateInstance constructor parameters. – Nikola Gaić Mar 22 '18 at 12:31
  • @series0ne That link does not describe how to get .net to resolve dependencies using Activator.CreateInstance – Cale Sep 06 '18 at 17:51
  • but how do I call this CreateInstance extension ... this doesn;t work : IMyCar car = ServiceProvider.CreateInstance(); – kahoona Jun 18 '20 at 09:31
  • @kahoona I would avoid using this implementation now. As stated, it's a little rough, and the built-in .NET Core DI stuff will do a better job (see the accepted answer). – Matthew Layton Jun 18 '20 at 09:42
  • 2
    oke but in the .NET Core way they say it's : var instance = (IPipe)ActivatorUtilities.CreateInstance(serviceProvider, pipeType); . But then you still need a ServiceProvider object :-(. I can't understand why they made it so difficult to just instantiate a class with DI in a self written class. – kahoona Jun 18 '20 at 14:25
0

Extension method:

public static class Extensions
{
    public static T BuildObject<T>(this IServiceProvider serviceProvider, params object[] parameters)
        => ActivatorUtilities.CreateInstance<T>(serviceProvider, parameters);
}

Usage:

[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
    var ss = HttpContext.RequestServices.BuildObject<SomeService>();
}