C# .NET CORE WEB.API — Inject Multiple Instance of some Interface
Let’s assume that we’re writing one ISomeService
interface and 3 different classes, SomeServiceA
, SomeServiceB
and SomeServiceC
implementing the interface.
public interface ISomeService{string Title { get; }}-=--=--=--=--=--=--=--=--=--=--=--=--=--=-
public class SomeServiceA: ISomeService{ public string Title { get { return "A"; } }}
-=--=--=--=--=--=--=--=--=--=--=--=--=--=-
public class SomeServiceB: ISomeService{public string Title { get { return "B"; } }}-=--=--=--=--=--=--=--=--=--=--=--=--=--=-
public class SomeServiceC: ISomeService{public string Title { get { return "C"; } }}
👎 Instead of registering them like this 👎
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ISomeService, SomeServiceA>(); services.AddTransient<ISomeService, SomeServiceB>(); services.AddTransient<ISomeService, SomeServiceC>();
}
😎 We are gonna extend Assembly like this 😎
public static class AssemblyExtension{public static IEnumerable<Type> GetTypesFrom<T>(this Assembly assembly){List<Type> types = new List<Type>();foreach (var type in assembly.DefinedTypes){if (typeof(T).IsAssignableFrom(type) && typeof(T) != type){types.Add(type);}}return types;}}
The main idea is that if in the future we add another class that will implement the ISomeService interface, we will not have to register it in the services 😀
- typeof(T) != type validate that we “skip” the interface :)
- From Microsoft —
IsAssignableFrom - Determines whether an instance of a specified type can be assigned to a variable of the current type.
And in the startup we gonna use it like this -
Assembly.GetEntryAssembly().GetTypesFrom<ISomeService>()
.ForEach((t) =>{
services.AddTransient(typeof(ISomeService), t);
});
(the ForEach extension for IEnumerable) —
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action){foreach (T element in source){action(element);}}
In the controller —
private readonly IEnumerable<ISomeService> _services;
.
.
.[HttpGet][Route(“{serviceType}”)]public IActionResult Get(string serviceType){var concreteService = _services.FirstOrDefault(service => service.Title.ToLower() == serviceType.Trim().ToLower());return Ok($”{concreteService.GetType().Name}”);}
- [Optional] — we can extract the validation logic of serviceType to ActionFilter Instead of doing it at the Controller (If serviceType is invalid, or empty, etc., etc., etc.)
Good Luck 🤞,
Eran Hadad