IOC
LinqPad Script: WeatherForecastR5.linq (12.09 kb)
I'll start at the end (literally) and give the key information you'll need to know about dependency injection. WebApi and ASP.NET Core applications use a dependency injection system to instantiate classes; in the case of this application, when a route is selected (figure 10b lines 211-213) the class for that route is instantiated and then invoked, e.g., HomePage, WeatherPage, and ToggleService.
the IOC system (which I'll just refer to as system) will look in its service collection registrations (figure 10a lines 174-183) to not only instantiate the class, but also provide its parameters. The registrations will tell the system how to instantiate a class, e.g., as Transient
(new instance each request), Scoped
(per session / request), and Singleton
(everyone shares the same instance). The difference between scoped and singleton is that if 5 people hit the Website at the same time, each will get their own scoped instance, which is isolated from the other 4 users. Within a session, the scoped instance behaves as a singleton, but only for that user. Where singletons instances will be shared by "every" user.
The system uses constructor injection
to instantiate and invoke the class [and its parameters]. By default, the system will look for the constructor with the largest number of parameters, get instances for each of the parameters, instantiate the class, and then invoke the class constructor with the parameters. All classes and parameters must be declared in the service registrations, aka "container".
Note that as each parameter is instantiated, that it's constructor parameters are also looked up in the container, instantiated and provided. This is referred to as propagating the dependency chain; as long as "new" is never used to instantiate a class (breaking the chain) then you'll be able to simply put an interface or class in any class constructor and the system will give you an instance for it.
Understanding this is the key, and paramount, to understanding the IOC/DI system. It is the essence of Inversion of Control (IOC), aka Dependency Injection (DI). Inversion of control meaning that instead of you instantiating a class, providing all of the constructor parameters, and invoking the class - the system does it for you.

Figure 1. Overview of application running
With basics out of the way. All that remains is understanding the function of each class. We'll cover each of the following with an overview of each classes code. You'll find that there is a clear separation of concerns with each having a single responsibility; there is not a lot of code in each class, it does one thing, and it does it well.

Figure 2. Skeleton view of application components
The following are the HomePage, WeatherPage, and ToggleService. For the home page we'll introduce a second IOC Unity Container, unlike the system's container, the Unity Container supports Setter injection
(discussed below) and allows you to register additional interfaces, classes, and factories on the fly. With the system container, you'll find that you can only register during system bootstrapping - once the container is built, you cannot add any more registrations.
You'll see that we provide an instance of IUnityContainer
[in image below] and use it to instantiate (resolve) the IWeatherFormatter instance. This uses a factory pattern, that based on the current value of IsJson (figure 10a lines 166-171) the container will provide either a JsonFormatter or TableFormatter instance.
Setter injection will kick in because these implementations of IWeatherFormatter
both have the property below;
[Dependency] Public IFoo Bar {get;set;}
The [Dependency] tells the Unity container that it needs to populate this property in the same manner as it does constructor parameters; it provides an instance. This is referred to as Setter injection
you'll find that the system and unity both use different values (reference figure 10b and the comments on line 198-203 as to why).
Armed with the knowledge of setter injection, you should now be able to look at the code in figure 9 for Foo and understand how the "Bar" class will return "This is FooBar" for it's GetMessage() function.

Figure 3. Pages and service
Below we see the results of the HomePage being clicked with the TableFormatter.

Figure 4. Home page
Below we show the results of the WeatherPage being clicked with TableFormatter

Figure 5. Weather forecast page
Below we show that the ToggleService will toggle the IsJson
property which is then returned (via bodyHtml) to the invoking process (in HtmlBase figure 11). Once the state is toggle any subsequent Home or Weather clicks will result in json being displayed.

Figure 6. Toggle service
Below is the key parts to the HtmlBase
, which our HomePage, WeatherPage, and ToggleService derive from.

Figure 7. HtmlBase class
Below we show our TableFormatter and JsonFormatter components

Figure 8. Formatters (json and html table)
We use IFoo to demonstrate how dependencies are propagated, and automagically populated, by either constructor or setter injection.

Figure 9. Foo
The magic happens in the container. The system will require that all dependencies are registered so that it knows how to instantiate a components lifetime (transient, scoped, or singleton) and provide an instance. Below the code is commented.

Figure 10a First part of WebAppBuilderExtension
Here we show how we can do a late registration (after build on line 204) and as a result change the setting for IFoo in the unity container - it will have a different implementation now then the system. We also demonstrate how MiddleWare can use these registrations - it will send information to the console base on the registered implementation of its constructor parameters.

Figure 10b Second part of WebAppBuilderExtension
GetHtml() below is how our pages display their content with javascript code handling button clicks and clock updates.

Figure 11. GetHtml() code
The decoupled nature of IOC / DI will allow for easy reuse of components as it is ultimately the container that can pick and chose its implementation for any of its interfaces.

Figure 12 - where the MiddleWare parameters are displayed