Dependency injecting primitive values in .NET

How to pass in primitive parameters to services in .NET DI Framework

Most code bases that have any form of separation of concern will also have dependencies between components. Instead of placing everything into one fat class that does everything, we depend on bits and pieces from all over the place, each with their own well-defined responsibilities.

public class MyService {
	private ComponentA _a;
	private ComponentB _b;

	public void doSomethingMeaningful(){
		// utilize a and b to do wonders!
	}
}

However, this prompts a new question, how do we actually populate our services with these other components? What if I wanted to switch out ComponentA with another one that has a slightly different implementation?

This is where dependency injection (DI) saves the day, it allows us to define dependencies externally from the code that uses them, even letting us abstract which implementation we wish to use.

With Microsoft’s DI framework (ASP.NET built-in) we can easily provide default implementations for abstract interfaces IComponentA and IComponentB.

var services = new ServiceCollection();
services.AddSingleton<IComponentA, DefaultComponentA>();
services.AddSingleton<IComponentB, DefaultComponentB>();
services.AddSingleton<MyService>();
public class MyService {
	private IComponentA _a;
	private IComponentB _b;
	
	public MyService(IComponentA a, IComponentB b){
		_a = a;
		_b = b;
	}
}

MyService will automatically be populated with its dependencies whenever they are needed.

Primitive parameters #

But what if we had a primitive parameter or a constant value that we also wish to provide to MyService?

public class MyService {
	private IComponentA _a;
	private IComponentB _b;
	private string _apiKey;
	
	public MyService(IComponentA a, IComponentB b, string apiKey){
		_a = a;
		_b = b;
		_apiKey = apiKey;
	}
}

This apiKey is not an object in itself, so it wouldn’t make any sense to call it a “service”.

Luckily the DI framework has another overloaded method that lets us call the constructor in a traditional fashion through a Func<IServiceProvider, TService> “implementation factory”.

services.AddSingleton(provider => 
	new MyService(provider.GetService<IComponentA>(), 
				  provider.GetService<IComponentB>(), 
				  "my_api_key_here"))

In this callback function we get access to provider, which can be utilized to retrieve any other dependencies that we desire!