Now, let’s analyze the consumer, an ASP.NET Core application that forwards HTTP requests to the façades and return the result as their response.The first step is to register the dependencies like this:
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddOpaqueFacadeSubSystem()
.AddTransparentFacadeSubSystem()
;
With these extension methods, the application root is so clean that it is hard to know that we registered two subsystems against the IoC container. This is a good way of keeping your code organized and clean, especially when you’re building class libraries.
Now that everything has been registered, the second thing we need to do is route those HTTP requests to the façades. Let’s take a look at the code first:
var app = builder.Build();
app.MapGet(
“/opaque/a”,
(IOpaqueFacade opaqueFacade)
=> opaqueFacade.ExecuteOperationA()
);
app.MapGet(
“/opaque/b”,
(IOpaqueFacade opaqueFacade)
=> opaqueFacade.ExecuteOperationB()
);
app.MapGet(
“/transparent/a”,
(ITransparentFacade transparentFacade)
=> transparentFacade.ExecuteOperationA()
);
app.MapGet(
“/transparent/b”,
(ITransparentFacade transparentFacade)
=> transparentFacade.ExecuteOperationB()
);
app.Run();
In the preceding block, we define four routes. Each route dispatches the request to one of the façade’s methods (highlighted code) using the façade that is injected in its delegate.If you run the program and navigate to the /transparent/a endpoint, the page should display the following:
Component A, Operation A
Component A, Operation B
Component B, Operation D
Component C, Operation E
What happened is located inside the delegates. It uses the injected ITransparentFacade service and calls its ExecuteOperationA() method, and then outputs the result variable to the response stream.Now, let’s define how ITransparentFacade is composed:
- ITransparentFacade is an instance of TransparentFacade.
- We inject IComponentA, IComponentB, and IComponentC in the TransparentFacade class.
- These dependencies are instances of ComponentA, ComponentB, and ComponentC, respectively.
Visually, the following flow happens:

Figure 11.17: A representation of the call hierarchy that occurs when the consumer executes the ExecuteOperationA method
In the preceding diagram, we can see the shielding that’s done by the façade and how it has made the consumer’s life easier: one call instead of four.
One of the hardest parts of using dependency injection is its abstractness. If you are not sure how all those parts are assembled, add a breakpoint into Visual Studio (let’s say, on the var result = transparentFacade.ExecuteOperationA() line) and run the application in debug mode. From there, Step Into each method call. That should help you figure out what is happening. Using the debugger to find the concrete types and their states can help find details about a system or diagnose bugs.
To use Step Into, you can use the following button or hit F11:

Figure 11.18: The Visual Studio Step Into (F11) button
Calling the other endpoints lead to similar results. As a reference, here’s the result from the other endpoints.Here’s the result for the /transparent/b endpoint:
Component B, Operation C
Component B, Operation D
Component C, Operation F
Here’s the results for the /opaque/a endpoint:
Component A, Operation A
Component A, Operation B
Component B, Operation D
Component C, Operation E
Here’s the result for the /opaque/b endpoint:
Component B, Operation C
Component B, Operation D
Component C, Operation F
Next, let’s update some results without changing the component’s code.