To add your own services to the DI framework, you simply implement Umbraco's IUserComposer interface. Umbraco will call the Compose() method it requires you to implement and in there you register any services you want to become injectable. This means other classes can request an instance of the registered service and it will be injected automatically. Using composers it's even possible to swap out Umbraco core services with your own implementations if that need ever arises. A great blog about composing in v8 was written by Umbraco Core developer Stephan, so for more information please give it a read.
Let me illustrate the basic concept with an extremely simple example.
I want to create a CalculatorService which offers just two methods: Sum() and Product() with predictable implementations. This service has the following tiny interface:
Internally, our concrete CalculatorService implementation depends on an ISumService and an IProductService to do the "heavy" lifting of actually adding and multiplying the arguments, both of which are injected. In addition to performing some simple arithmetic, we want to log every call to Sum() and Product() and utilize Umbraco's standard logger for this. This is where you can see the power of DI, as the only thing necessary to obtain a logger instance is to specifcy an ILogger dependency in the constructor of the CalculatorService, and it will be injected automagically. Umbraco will register its ILogger implementation with the DI container, but does not know about an ISumService, IProductService or ICalculatorService, as those are our own services. We will have to register those ourselves by implementing the IUserComposer interface discussed earlier. For our Calculator, the implementation will look like this:
The CalculatorService itself is straightforward and simply uses its injected services to perform a calculation and log the result as well.
The CalculatorService is now ready to be used throughout our application, without having to worry about creating any of its dependencies. To make the Sum and Product methods available to the world, let's expose it through a Web API. We create a very simple CalculatorApiController which provides access to both Sum() and Product() through HTTP GET requests.
That's it. The controller requests its ICalculatorService dependency and the DI framework takes care of creating an instance together with all its dependencies.