Reputation: 11
Recently, I work with ASP Boilerteample. It has classes to implement dependency injection such as ITransientDependency
.
When a class implements the ITransientDependency
interface, it can be injected into the constructor without any configuration in the startup file.
I want to do the same but don't know how. Please tell me what to do, is there a library to support or a document.
Upvotes: 0
Views: 1784
Reputation: 493
You can do this via reflection, however it is not trivial.
The following assumes you have a Dependency Injection container set up.
First you need to get all the types from all current assemblies, but only those that are not abstracts or interfaces (i.e. those that can be created):
var types = from t in AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
where t.IsAssignableFrom(typeof(ITransientDependency))
&& !t.IsAbstract && !t.IsInterface
select t;
This will return a list of Type
objects representing classes that implement ITransientDependency
from all currently loaded assemblies.
Next, you need to add those to the Dependency Injection container. Assuming you are using Microsoft's IServiceCollection
you then do this (e.g. in the ConfigureServices
method in your Startup class):
foreach (var t in types)
{
services.AddTransient(t);
}
Note: this is not really DI best practice. Normally you should inject interfaces, not implementations, and add each one like this:
services.AddTransient<ISomeDependency, SomeImpl>();
services.AddTransient<IAnotherDependency, AnotherImpl>();
// and so on
This helps with test-driven development, as you can create a mock implementation of an interface, but not of an implementation.
Finally, you can now inject these into a class via the constructor:
public class SomeClass
{
public SomeClass(SomeDependency dep)
{
// do something
}
}
You need to be careful doing this as you could introduce issues at runtime - for example, the dependencies of all your ITransientDependency
implementations also need to be added to your DI container, and they can't have any other dependencies (e.g. value types).
The GetTypes()
method used in the first step can throw an exception so you would need to handle that. I have done this in the past through pushing this into an extension method:
internal static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}
Upvotes: 3