Recently I have inherited an ASP.NET core application, which is also my first time working with the framework. Working with the application initializing controllers felt very repetitive since all controllers used a few common services like loggers. ASP.NET core makes service access easy with dependency injection, but it’s challenging to stay true to the DRY principle when every controller is initialized with the same few services.
In the code above, a few of the services being injected are also being used in other controllers. So, it becomes very repetitive to have to initialize all controllers the same way. But moving the injection of common services to a base controller will not work, as seen below.
Having the common service injected in a base controller constructor will defeat the purpose of a base controller and become redundant. The services still need to be defined in each child controller.
Solution
Create Properties Instead
What I found to work best for my needs and the application is to define all common services as properties. With ASP.NET Core the Microsoft.Extensions.DependencyInjection name space gives us access to the following extension method HttpContext.RequestServices.GetService<T>.
Caution
With this approach, one thing to keep in mind is that it uses the HttpContext object, and if it is not available, you will not be able to use the service. And remember the services still need to be registered in the Startup.cs > ConfigureServices method.
Base Controller
Child Controller
Now controllers are only required to inject the services specific to them. Thus, sticking to the DRY principle and keeping the controller constructors clean.
Side note, Microsoft seems to prefer injection over RequestServices:
The services available within an ASP.NET Core request are exposed through the HttpContext.RequestServices collection. When services are requested from inside of a request, the services and their dependencies are resolved from the RequestServices collection.
The framework creates a scope per request and RequestServices exposes the scoped service provider. All scoped services are valid for as long as the request is active.
Note: Prefer requesting dependencies as constructor parameters to resolving services from the RequestServices collection. This results in classes that are easier to test.
Keep Reading: C# Windows Service Debug Hack >>