13

New aspnet has in-build dependency injection: Startup class instance receives services, controllers, view components do. Is there any way for me to create object of my class and pass services using aspnet functionality? Something like:

WebApplicationClassesActivator.Create(typeof(MyClass))

where MyClass contains constructor receiving IHostingEnvironment instance, for example.

Real usage:

public class MyController : Controller
{
    private readonly IContext Context;
    public MyController(IContext context)
    {
        Context = context;
    }
    public IActionResult Index(string className)
    {            
        return View(WebApplicationClassesActivator.Create(Type.GetType(className)));
    }
}

Where classsName is name of classes like:

public class A
{
    public A(IContext context, IHostingEnvironment env)
    {
       ...
    }
}
FLCL
  • 2,445
  • 2
  • 24
  • 45
  • Can you elaborate more? Right now it is not quite clear - what are you trying to do. Are you trying to bind some interface to implementation using ASP.NET builtin DI container? Then look to the `services.AddTransient` and so on. – Andrey Korneyev Jan 12 '16 at 13:29
  • Yes, I added some transients, a scoped and a singleton in Startup and in controller action I create an instance of another my class and want to pass some services(standard and added by me too) – FLCL Jan 12 '16 at 13:31
  • It is still not quite clear what is your problem. Can you illustrate it with code samples? – Andrey Korneyev Jan 12 '16 at 13:32
  • And my class get known only at runtime – FLCL Jan 12 '16 at 13:33
  • @AndyKorneyev, example added – FLCL Jan 12 '16 at 13:39
  • 1
    Well, from my point of view your scenario has nothing to do with DI since it is simply creation of instance by type name (howewer it *slightly* looks like service location in application code instead of real injection of dependency using constructor injection, for example - thus looks like an antipattern) . Why don't just `Activator.CreateInstance(Type.GetType(className))` in your particular case? Am I missing something? – Andrey Korneyev Jan 12 '16 at 13:52
  • 1
    @AndyKorneyev simply because `className`-class has constructor which needs `IContext`, `IHostingEnvironment`, etc implementations instances to be passed into. – FLCL Jan 12 '16 at 13:59
  • @FLCL, Does it has do be vanilla .NET? Or can a dependency resolver like Unity be used? – smoksnes Jan 12 '16 at 14:18

2 Answers2

28

Assembly Microsoft.Extensions.DependencyInjection.Abstractions contains static class ActivatorUtilities which has what I need:

public static object CreateInstance(IServiceProvider provider, 
                                    Type instanceType, 
                                    params object[] parameters);

and I can create instance and inject services:

private readonly IServiceProvider Provider;

public HomeController(IServiceProvider provider)
{       
    Provider = provider;
}

public IActionResult Index()
{       
    var instance = ActivatorUtilities.CreateInstance(Provider, typeof(A));

    return View(instance);
}

public class A
{
    public A(IContext context)
    {

    }
}
FLCL
  • 2,445
  • 2
  • 24
  • 45
2

Well, you can do it in the following manner:

public class MyController : Controller
{
    private readonly IContext Context;
    private readonly IServiceProvider _Provider;

    public MyController(IContext context, IServiceProvider provider)
    {
        Context = context;
        _Provider = provider;
    }

    public IActionResult Index(string className)
    {            
        return View(_Provider.GetService(Type.GetType(className)));
    }
}

Surely each class you're planning to instantiate in such a way should be added in ConfigureServices something like:

services.AddTransient<MyClass, MyClass>();

Also notice - this implementation in fact service locator, which is frequently considered as design antipattern.

Andrey Korneyev
  • 26,353
  • 15
  • 70
  • 71
  • I don't think that, for example, every Controller class descendant will be added to services to allow creation of it. – FLCL Jan 12 '16 at 14:27
  • Huh? What controller descendants you're talking about? Phrase concerning instantiation was about "className" argument of action method - class having such a name should be added to services in order for DI container to be able to resolve it. If it is not suitable to you - then possibly you should use another DI container, not builtin one. – Andrey Korneyev Jan 12 '16 at 14:36
  • But your attempt still require class `A` to be added to services in order for serviceprovider to be able to resolve it. Or am I still missing something? – Andrey Korneyev Jan 12 '16 at 14:48
  • 3
    No, it is not. Services in DI are used to be constructor parameters, so that is why they are stored somewhere in DI engine. So other objects which need in these services will interact with DI only on creation step. – FLCL Jan 12 '16 at 14:49
  • 1
    Hmmm.. it looks like it was a gap in my knowledge of vNext DI. ;) – Andrey Korneyev Jan 12 '16 at 14:54