❔ Understanding inheritance
Hello, im trying to understand a webshop example from microsoft. Im trying see what GetCardTypesAsync() does. (Attatched is the code from OrdersController)
When peeking the definition i only get to the interface "IOrderQueries" used by the OrdersController. I find the original function in another cs file "OrderQueries" (by searching for the function name) which inherits the interface but i really cant understand the connection between Orderqueries, the interface IOrderQueries and OrdersController. How does GetCardTypesAsync() in OrdersController know to use the function declared in OrderQueries just by using a interface? Anyone see what i dont? Let me know if you need additional info 🙂 Thanks in advance!
When peeking the definition i only get to the interface "IOrderQueries" used by the OrdersController. I find the original function in another cs file "OrderQueries" (by searching for the function name) which inherits the interface but i really cant understand the connection between Orderqueries, the interface IOrderQueries and OrdersController. How does GetCardTypesAsync() in OrdersController know to use the function declared in OrderQueries just by using a interface? Anyone see what i dont? Let me know if you need additional info 🙂 Thanks in advance!
17 Replies
My guess is its thanks to the dependency injection in OrdersController.
But if you inject the dependency to the IQueryInterface, how does that make the function from OrderQueries avaliable?
that's what DI does
it provides concrete instances of interfaces & classes
in the example ms apparently chose to implement
IOrderQueries
in a class called OrderQueries
and registered it in the DI-container as the implementation
so whenever a class (for example one of the controllers) asks for a dependency of type IOrderQueries
it will be given a instance of OrderQueries
the controllers don't need to worry what concrete class it is. all it cares that it implements IOrderQueries
. that's part of the problem DI/IoC try to solve 😉Great anser, thanks! I think i kinda get it! So when you instantiate the interface it will include all the classes that implemts the interface? Made a small sketch to visualise my thought, am i getting it correctly? 🙂
there can be multiple classes implementing the interface
but in you DI-container you will register one of them as the default implementation for the interface
(basically saying "whenever someone asks for interface
IOrderQueries
give them an object of class OrderQueries
")
so when Class2
or OrdersController
need a IOrderQueries
they will be given an OrderQueries
you cant instantiate an interface. you can only instantiate classes that implement an interface 😉
interfaces are a little bit like a specification. they describes how classes should look like, to allow certain scenarios (in this case "querying orders")Ahh okey now i think i get it - you declare in the DI-container the terms of which class that should be used. There i can see it being very useful, only the class that is needed for the specfic class/situation is instantiated.
I think my confusion comes from that i cant see where the class OrderQueries "selected as the class to instantiate", but that is done in the DI then?
This might be a stupid question but can i find the DI-container and how does it tell which class that are needed? Im looking for the class or file that tells the program which class that should be implemented. There are alot of files in this project, are there any general naming conventions or such that can help me find the DI-container? 🙂
there probably is a class
Startup
that contains a function ConfigureServices
. in there the registrations for DI are done (should use functions like AddScoped<...>(...)
or AddTransient<...>(...)
alternatively it might be done directly in the Program
classThank you!
This is from the startup file, my guess is that the logic which class that is "selected"(for example as default) comes from one of these lines, am i correct? 🙂
.AddApplicationInsights(Configuration)
.AddCustomMvc()
.AddHealthChecks(Configuration)
.AddCustomDbContext(Configuration)
.AddCustomSwagger(Configuration)
.AddCustomIntegrations(Configuration)
.AddCustomConfiguration(Configuration)
.AddEventBus(Configuration)
.AddCustomAuthentication(Configuration);
As a example, if you were to change which class is given as default, you would have to look into one of the mentioned above? 🙂
yes those functions will register a bunch of services at once
if you want to override the registration you can simply call the appropriate
AddScoped<...>(...)
/AddTransient<...>(...)
/AddSingleton<...>(...)
after those functions
like services.AddScoped<IOrderQueries, MyNewOrderQueries>()
, will use MyNewOrderQueries
instead of the "normal" OrderQueries
Ah okey, i think i just realised something! Whenever i add something to IServiceCollection services i can say that i added it to the DI-container, right?
For example:
.Service.AddMVC just adds the classes that are needed for MVC to the DI-container? -> and are therefore avaliable in whatever class we instantiate it in? 😄
yes
IServiceCollection
is microsofts DI-container that comes with asp.net (can be used in other apps too)
there are other DI-containers too, but since this one is the default, it has become the most popular ... or at least the most known one 😉
"DI-container" is a more general term, so to sayDamn, my mind is blown! Ive had such a hard time grasping the whole DI-container term. Cant thank you enough!
Something that still is a bit vague to me is where the conditions or default class is set for the interface. I attached the Startup file and added a comment under CunfigureServices. Im thinking it would look something like this:
Im having a hard time to really understand everything in the startup file, maybe there is a conditions that ish-does what i mentioned above but that i just cant relly see it with my own eyes. Can you tell? Or maybe i misunderstood something? 🙂
@icebear
this seems to be a more complicated example
it is using autofac for DI (as is said there are multiple DI-containers)
first it registers a bunch of services in
IServiceCollection
then creates a autofac container and populates it with the registrations from IServiceCollection
(var container = new ContainerBuilder(); container.Populate(services);
)
then it registers two modules to the autofac-container container.RegisterModule(new MediatorModule()); container.RegisterModule(new ApplicationModule(Configuration["ConnectionString"]));
in the ApplicationModule
there is the registration for IOrderQueries
:
Okey, so in a way this solution is using two DI-containers? IserviceCollection and autofac or is autofac an extension of IserviceCollection?
Another question since im not that experienced with lambda expressions. If you were to transform the code below into words, can you say:
- When something is registred, is it of type IOrderQueries
-> return a OrderQueries object? 🙂
kinda yes. most libraries provide those
Add*()
functions that work with IServiceCollection
that's why it first uses IServiceCollection
and then copies over the registration into the autofac-container (that is going to be used from then on)
and yes the lambda basically will be called anytime a object for IOrderQueries
needs to be createdOkey perfect, then i think i understand. Cant thank you enough, great educator, great answers and maybe even greater patience with a noob like me 😉 you made my day!
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.