Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resolve un-registered type using standard MVC Core dependency injection

Tags:

Is there a way to get IServiceProvider.GetService<T> to return an instance even if T is not explicitly registered with the container?

If I know that T has dependencies I'd like them to be injected based on their registrations without having to register T itself.

I believe Ninject will intelligently work out the most appropriate constructor or fallback to a parameterless constructor if no suitable constructor is found. I'd like to replicate this behaviour using the standard MVC Core DI framework if possible.

like image 887
Red Taz Avatar asked Jul 04 '16 10:07

Red Taz


People also ask

How can dependency injection be resolved?

Resolve dependencies using IServiceProvider You can use the IServiceCollection interface to create a dependency injection container. Once the container has been created, the IServiceCollection instance is composed into an IServiceProvider instance. You can use this instance to resolve services.

Can we inject dependency in Viewcomponent?

Framework level dependency injection is powerful feature of . NET Core. It is easy to configure and easy to use through constructor injection. We used dependency injection with view component to display top menu and to correctly highlight current top level category.

What is dependency injection in core MVC?

Dependency injection (also known as DI) is a design pattern in which a class or object has its dependent classes injected (passed to it by another class or object) rather than create them directly. Dependency injection facilitates loose coupling and promotes testability and maintenance.

How do you dispose of resources using dependency injection?

When you make it explicit, you've got basically two options: 1. Configure the DI to return transient objects and dispose these objects yourself. 2. Configure a factory and instruct the factory to create new instances.


2 Answers

To keep this up to date: There is a way to achieve exactly what you are looking for.

Standard dependency injector of .NET Core

In my sample i create a new instance of IServiceCollection for showcase:

var services = new ServiceCollection(); var serviceProvider = services.BuildServiceProvider(); var unregisteredClassInstance =      ActivatorUtilities.CreateInstance<UnregisteredClass>(serviceProvider); 

This gives you an instance of the type UnregisteredClass which was not previously registered, but takes constructor parameters which are registered previously on the ServiceCollection.

Third party dependency injectors

SimpleInjector can do that easily with container.GetInstance<UnregisteredClass>();.

like image 169
Alpox Avatar answered Jan 01 '23 21:01

Alpox


While there is no way provided by default to resolve un-registered concrete types you can add an extension function that will give you the ability. Its important to note that this can be abused as a service locator which is an Anti-pattern. Depending on your usage its possible to take advantage of this without turning it into a service locator.

using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text;  namespace Microsoft.Extensions.DependencyInjection {     public static class ServiceProviderExtensions     {         public static TService AsSelf<TService>(this IServiceProvider serviceProvider)         {             return (TService)AsSelf(serviceProvider, typeof(TService));         }         public static object AsSelf(this IServiceProvider serviceProvider, Type serviceType)         {             var constructors = serviceType.GetConstructors(BindingFlags.Public | BindingFlags.Instance)                 .Select(o => o.GetParameters())                 .ToArray()                 .OrderByDescending(o => o.Length)                 .ToArray();              if (!constructors.Any())             {                 return null;             }              object[] arguments = ResolveParameters(serviceProvider, constructors);              if (arguments == null)             {                 return null;             }              return Activator.CreateInstance(serviceType, arguments);         }          private static object[] ResolveParameters(IServiceProvider resolver, ParameterInfo[][] constructors)         {             foreach (ParameterInfo[] constructor in constructors)             {                 bool hasNull = false;                 object[] values = new object[constructor.Length];                 for (int i = 0; i < constructor.Length; i++)                 {                     var value = resolver.GetService(constructor[i].ParameterType);                     values[i] = value;                     if (value == null)                     {                         hasNull = true;                         break;                     }                 }                 if (!hasNull)                 {                     // found a constructor we can create.                     return values;                 }             }              return null;         }     } } 
like image 43
Matt M Avatar answered Jan 01 '23 22:01

Matt M