I recently thought about a case where i can build the abstractions of news importer into the .NET DI Contianer.
This is my example Case.
This class represents a news source.
public abstract class Source {
public Guid Id {get; set;}
}
This concrete Source is a Rss Feed.
public class RssFeed: Source {
public string Url {get; set;}
}
Now i have a generic interface for an importer of some source.
public interface ISourceImporter<TSource> where TSource: Source {
Task IEnumerable<Post> ImportAsync(TSource source)
}
And a concrete Implementation for the RssFeed Sorce
public class RssFeedImporter: ISourceImporter<RssFeed> {
}
Register the Service into the DI Container
services.AddSingleton<ISourceImporter<RssFeed>, RssFeedImporter>()
So the Main problem ooccurs at the usage of the service throug the ServiceProvider. I my Command i want to abstract the concrete type of my source like this.
public Task ImportCommand(Source source) {
ISourceImporter<Source> importer = (ISourceImport<Source>)serviceProvider
.GetRequiredService(typeof(ISourceImporter<>).MakeGenericType(source.GetType()))
var posts = await importer.ImportAsync(source);
}
Is there a way to build that abstraction with the .NET Dependency Container? Maybe is my structure not suitable for this? I read an article about open generics but this gives me a circular dependency when building the DI Container.
Thanks for your help.
If the solution can't be solved by turning
ImportCommand(Source)into anImportCommand<TSource>(TSource source) where TSource : Source, you will have resort to using Reflection.The easiest way (least amount of code) is by making use of the
dynamickeyword:But note the following:
ImportAsyncwill fail when you refactor the interface. That, however, is easily solved by writing a unit test forImportCommand.ImportAsyncwill fail when theISourceImporter<T>implementation is internal, even if the interface is public.