DALL·E: looking into an empty packing box in a busy room with a claymation office in the background

Creating an Empty Service Provider

Here's a simple demonstration of creating an empty Microsoft.Extensions.DependencyInjection.ServiceProvider instance. We start off as simply as possible by creating an empty service provider: there's nothing in it (so it can’t actually provide any services). However, this allows us to skip all the complications that arise when adding services.

It's important to remember that service providers are objects just like any other: they have a type, and they can be created. So just as with any other object, the first step is getting a toy instance to play with. An empty service provider is exactly that.

Creating an Empty Service Provider

So let's go! With explanations to follow, here’s how you create an empty service provider:

// Requires the Microsoft.Extensions.DependencyInjection NuGet package.

using Microsoft.Extensions.DependencyInjection;

static void CreateEmptyProvider()
{
    ServiceCollection serviceCollection = new ServiceCollection();

    ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();

    // Now you have an empty service provider.
}
        
You can see the code in GitHub, here: https://github.com/davidcoats/D8S.E0002.

What NuGet packages are needed?

You need a reference to the Microsoft.Extensions.DependencyInjection NuGet package. You can use any version you want, but for this article I used Version 5.0.2.:
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2"/>

What namespaces are needed?

We’ll only need one namespace: “Microsoft.Extensions.DependencyInjection”:

using Microsoft.Extensions.DependencyInjection;
    

What is the code doing?

It's simple:
  1. Create a ServiceCollection instance,
  2. Then call the BuildServiceProvider extension method,
  3. This gives you a ServiceProvider instance.
While each step might be simple, each step is important, and all steps are required.

A service provider needs to know what services exist in your program, and you tell your service provider this by adding services to a service collection. You might think it would be easy for a program to “just take care of it” and add the right services for you (perhaps by just magically adding all services your program can find within all the libraries it references). But there could be different implementations of a service in the same library, only one of which you want to use. Or there could be different services based on whether you are running in development or in production. Or you might want to add services in a specific order, so that if the first one has an error, then next one is used. All of these real-world complications mean it’s just better for you to explicitly list which services you want.

Next, after listing out your services, you build a service provider from the service collection. It’s very important that after building the service provider, the list of services does not change. If the list did change, people who were counting on a service being available, or that a service behaves in a certain way, or that a service is *not* available, would all be confused. Imagine if your favorite airline stopped flying to a city, or started charging extra baggage fees, or even went crazy and started driving you by bus... Yes, all of these things have happened, but they caused confusion, and you don’t want any confusion inside your program! That’s why the service provider and service collection are different, and a service provider is built from a service collection just once, at a single point in time.

Finally, you want to keep track of individual service provider object instances (as opposed to having a single service provider for your whole program). Your program might have multiple co-existing service providers, such as in ASP.NET when each request to your webserver gets its own special(scoped) copy of the main service provider that exists only for the duration of handling the request. You can also have services that do their job using their own internal service provider (as, for example, Entity Framework does for database access). So it’s important to have service provider functionality bundled up in individual object instances, not program - wide single static instances.

But forget all of this: while service providers can be used in complex ways, the important thing is that getting started is very simple.

Why?

Why an empty service provider? An empty service provider, because it's empty, can't provide any services. And the name "service provider" implies that the point of a service provider is to provide services.

Why would I make a whole blog post demonstrating how to make an empty service provider if it's basically useless?

One reason is that service providers are certainly very important: they are the heart of dependency injection in ASP.NET. Behind every web request is a service provider that is actually doing the work of creating all your views, controllers, and services. However, while service providers are everywhere in ASP.NET, they are usually never seen since the ASP.NET framework magically takes care of them. This can make service providers seem mysterious, and that is a problem for something so important. Too often I’ve seen friends suffer anxiety caused by this combination of mysteriousness and importance, and I want to fix that! Any anxiety suffered over service providers is a real shame since service providers are real simple.

So the short answer is that I could not find a simple demonstration of creating an empty service provider on the internet. I hesitate to say that it doesn't exist, but I couldn’t find it. A Google search for create an empty service provider returned:
  • Stack Overflow – Too complicated: hosting environment, argument parsing, MVC, showing adding a singleton service (what’s that?), and then getting services, all mixed up together.
  • Microsoft Documentation – Assumes that of course you know that service providers mean “dependency injection” and that dependency injection is another name for “dependency inversion”, which is an Inversion-of-Control technique.
  • Steve J. Gordon – Even the most basic example by one of my.NET blogger heroes also tacked on adding singleton services as classes and interfaces(both can be services ?), and then continues on to discuss validating scopes(?) and talking about service provider engines(are those different from service providers?).
I couldn’t find it, so I created it.

The long answer is that an empty service provider is the simplest possible service provider that still exists.

As simple as possible, but no simpler.

-- Albert Einstein

An empty service provider is the ideal starting point for further investigations into service-based architectures. You can learn how to add and get services. You can investigate what happens when you ask for a service that doesn’t exist. You can ask where there’s really no services an empty service provider can provide... But! Knowing how to create an empty service provider instance is the starting point for each and every one of all these grand adventures.

Now what?

Now that you know how to create an empty service provider, the next steps are to:
  1. Add services to a service provider, then
  2. Get instances of these services from a service provider.
For this post, I wanted to show the simplest possible thing you could do with a service provider. But stay tuned. I’ll cover these in the future.