17

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!?

9
  • Where/how you you want to create the object? Commented Oct 30, 2016 at 22:37
  • @Nkosi In the Main method of a console app...something like SomeObject x = startup.ServiceProvider.ResolveDependenciesFor<SomeObject>(); Commented Oct 30, 2016 at 22:39
  • Relevant question: stackoverflow.com/questions/31863981/… Commented Oct 30, 2016 at 22:41
  • relevant article: msdn.microsoft.com/en-us/magazine/mt707534.aspx Commented Oct 30, 2016 at 22:42
  • 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 Commented Oct 30, 2016 at 22:46

3 Answers 3

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

Sign up to request clarification or add additional context in comments.

Comments

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;
        }
    }

10 Comments

How is this using the IServiceProvider to instantiate the object (with all dependencies injected)?
@alexw .Select(o => provider.GetService(o))
@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.
@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... joonasw.net/view/aspnet-core-di-deep-dive
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.
|
1

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>();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.