This is a form of dependency injection.
Simply put, there exists some kind of registry which tells the runtime that "if you're creating an instance of Foo
and it needs a parameter of type IBar
, create a Bar
instance and pass it as the parameter value".
In default .NET Core, this registry is called the service collection, and once configured, the service provider does the actual instantiation based on what you configured in the service collection.
There are other libraries, e.g. AutoFac, which provide a similar experience.
Somewhere in your Startup.cs
, the IServiceCollection
is being told what IQueryPipe
and ICommand
should be. This could be in there explicitly, e.g.:
services.AddScoped<IQueryPipe, MyQueryPipe>();
services.AddScoped<ICommand, MyCommand>();
Or it could be hidden behind another method which would in turn perform the above steps:
services.UseMyLibrary();
Or there are plenty of other clever ways to have these dependencies registered into the service collection.
The point here is that someone has registered the correct instance to the interface type you see in the controller's constructor, and this information is used when the runtime tries to instantiate an instance of your controller.
If not every constructor parameter could be resolved (i.e. it was not registered properly), then the service provider would not be able to instantiate your controller and you would get a runtime exception.
ConfigureServices
, where instances ofIQueryPipe
andICommand
are configured. This adds them to the built in dependency injection container, which then does some reflection-based magic during startup, figures out that the ProductController needs these two services, and injects the configured ones. See this and this