GetService or GetRequiredService in IServiceProvider?

Published: Monday 14 July 2025

The IServiceProvider is responsible for resolving types registered for dependency injection. But should you use GetService or GetRequiredService to resolve a dependency?

Injecting it into a controller

First, we need to know how to inject it. You inject it into a controller by declaring the IServiceProvider type in the constructor's parameter and storing the instance in a readonly field.

These are the classes we've set up:

public interface ICategoryService
{
	CategoryTypeDto? GetCategoryType(int id);
}

public interface ICategoryStorageService
{
	List<CategoryTypeDto> Types { get; }
}

public class CategoryService : ICategoryService
{
	private readonly ICategoryStorageService _categoryComputersStorageService;

	public CategoryService([FromKeyedServices("computers")] 
		ICategoryStorageService categoryComputersStorageService)
	{
		_categoryComputersStorageService = categoryComputersStorageService;
	}

	public CategoryTypeDto? GetCategoryType(int id) => 
		_categoryComputersStorageService.Types.SingleOrDefault(s => s.Id == id);
}

public class CategoryComputersStorageService : ICategoryStorageService
{
	public List<CategoryTypeDto> Types { get; } = new()
	{
		new(2, "Computers"),
		new(4, "Software")
	};
}

public record MvcServiceProviderModel(
	CategoryTypeDto? GetServiceCategory,
	CategoryTypeDto? GetRequiredServiceCategory,
	CategoryTypeDto? GetKeyedServiceCategory,
	CategoryTypeDto? GetRequiredKeyedServiceCategory
);

And this is how we've registered them in Program.cs:

// Program.cs
builder.Services.AddScoped<ICategoryService, CategoryService>();
builder.Services.AddKeyedSingleton<ICategoryStorageService, CategoryComputersStorageService>("computers");

Both the GetService and GetRequiredService methods allow you to resolve a service that has been registered with dependency injection. You can use the GetKeyedService or the GetRequiredKeyedService method to do the same thing with keyed services.

// MvcController.cs
[Route("[controller]")]
public class MvcController : Controller
{
	private readonly IServiceProvider _serviceProvider;

	public MvcController(
		IServiceProvider serviceProvider
	)
	{
		_serviceProvider = serviceProvider;
	}

	[HttpGet("service-provider")]
	public IActionResult ServiceProvider()
	{
		return View(new MvcServiceProviderModel(
			type,
			_serviceProvider.GetService<ICategoryService>()?.GetCategoryType(2),
			_serviceProvider.GetRequiredService<ICategoryService>().GetCategoryType(2),
			_serviceProvider.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2),
			_serviceProvider.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2)
		));
	}
}

Similar story with an MVC view

You use the @inject directive to inject the IServiceProvider into an MVC view. From there, you can use the extension methods to inject methods that have been registered with dependency injection using GetService, GetRequiredService, GetKeyedService and GetRequiredKeyedService.

<!-- ServiceProvider.cshtml -->
@using RoundTheCode.DI.Enums
@using RoundTheCode.DI.Models
@using RoundTheCode.DI.Services.Category
@inject IServiceProvider serviceProvider
@model MvcServiceProviderModel
<h2>View</h2>
<p>GetServiceCategory = @(serviceProvider.GetService<ICategoryService>()?.GetCategoryType(2))</p>
<p>GetRequiredServiceCategory = @(serviceProvider.GetRequiredService<ICategoryService>().GetCategoryType(2))</p>
<p>GetKeyedServiceServiceCategory = @(serviceProvider.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2))</p>
<p>GetRequiredKeyedServiceCategory = @(serviceProvider.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2))</p>

Another way to get the instance

With either a controller or MVC view, you can also use the HttpContext to get the IServiceProvider instance. You do that by calling HttpContext.RequestServices.

// MvcController.cs
[Route("[controller]")]
public class MvcController : Controller
{
	[HttpGet("service-provider")]
	public IActionResult ServiceProvider()
	{
		return View(new MvcServiceProviderModel(
			HttpContext.RequestServices.GetService<ICategoryService>()?.GetCategoryType(2),
			HttpContext.RequestServices.GetRequiredService<ICategoryService>().GetCategoryType(2),
			HttpContext.RequestServices.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2),
			HttpContext.RequestServices.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2)
		));
	}
}

With an MVC view, you can get the HttpContext from the ViewContext instance.

<!-- ServiceProvider.cshtml -->
@using RoundTheCode.DI.Enums
@using RoundTheCode.DI.Models
@using RoundTheCode.DI.Services.Category
@model MvcServiceProviderModel
<h2>View</h2>
<p>GetServiceCategory = @(ViewContext.HttpContext.RequestServices.GetService<ICategoryService>()?.GetCategoryType(2))</p>
<p>GetRequiredServiceCategory = @(ViewContext.HttpContext.RequestServices.GetRequiredService<ICategoryService>().GetCategoryType(2))</p>
<p>GetKeyedServiceServiceCategory = @(ViewContext.HttpContext.RequestServices.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2))</p>
<p>GetRequiredKeyedServiceCategory = @(ViewContext.HttpContext.RequestServices.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2))</p>

The difference between GetService and GetRequiredService

Both the GetService and GetRequiredService methods in IServiceProvider resolve a type if it has been registered in dependency injection. But they behave differently if the service hasn't been registered.

The GetService method will return null if it has not been registered. Whereas if you use the GetRequiredService method and the service has not been registered, you'll get the following runtime exception:

System.InvalidOperationException: No service for type '{Type}' has been registered.

It's a similar story if you use the GetKeyedService method which will return null for a non-registered service and the same exception when using the GetRequiredKeyedService method.

Using IServiceProvider in other areas

You can use IServiceProvider in other areas of ASP.NET Core.

Web API controller

In a Web API controller, you either pass in the IServiceProvider instance as a constructor parameter and store a reference, or you can pass it in as a parameter in the method endpoint:

// WebApiController.cs
[ApiController]
[Route("api/[controller]")]
public class WebApiController : ControllerBase
{
	private readonly IServiceProvider _serviceProvider;

	public WebApiController(
		IServiceProvider serviceProvider
	)
	{
		_serviceProvider = serviceProvider;
	}

	[HttpGet("service-provider")]
	public IActionResult ServiceProvider()
	{
		return Ok(new
		{
			GetServiceCategory = _serviceProvider.GetService<ICategoryService>()?.GetCategoryType(2),
			GetRequiredServiceCategory = _serviceProvider.GetRequiredService<ICategoryService>().GetCategoryType(2),
			GetKeyedServiceCategory = _serviceProvider.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2),
			GetRequiredKeyedServiceCategory = _serviceProvider.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2)
		});
	}

	[HttpGet("service-provider-parameter")]
	public IActionResult ServiceProviderParameter(IServiceProvider sp)
	{
		return Ok(new
		{
			GetServiceCategory = sp.GetService<ICategoryService>()?.GetCategoryType(2),
			GetRequiredServiceCategory = sp.GetRequiredService<ICategoryService>().GetCategoryType(2),
			GetKeyedServiceCategory = sp.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2),
			GetRequiredKeyedServiceCategory = sp.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2)
		});
	}
}

You can also use HttpContext.RequestServices to get the instance of the IServiceProvider.

// WebApiController.cs
[ApiController]
[Route("api/[controller]")]
public class WebApiController : ControllerBase
{
	[HttpGet("service-provider")]
	public IActionResult ServiceProvider()
	{
		return Ok(new
		{
			GetServiceCategory = HttpContext.RequestServices.GetService<ICategoryService>()?.GetCategoryType(2),
			GetRequiredServiceCategory = HttpContext.RequestServices.GetRequiredService<ICategoryService>().GetCategoryType(2),
			GetKeyedServiceCategory = HttpContext.RequestServices.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2),
			GetRequiredKeyedServiceCategory = HttpContext.RequestServices.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2)
		});
	}
}

Minimal APIs

With minimal APIs, you can pass in the IServiceProvider instance as a parameter for each endpoint:

app.MapGet("/minimal/service-provider", (
    IServiceProvider serviceProvider
) => {
	return new
	{
		GetServiceCategory = serviceProvider.GetService<ICategoryService>()?.GetCategoryType(2),
		GetRequiredServiceCategory = serviceProvider.GetRequiredService<ICategoryService>().GetCategoryType(2),
		GetKeyedServiceCategory = serviceProvider.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2),
		GetRequiredKeyedServiceCategory = serviceProvider.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2)
	};
});

To use HttpContext.RequestServices, you'll need to pass in the HttpContext type as a parameter. You can then use that instance to get the RequestServices property.

app.MapGet("/minimal/service-provider", (
    HttpContext httpContext
) => {
	return new
	{
		GetServiceCategory = httpContext.RequestServices.GetService<ICategoryService>()?.GetCategoryType(2),
		GetRequiredServiceCategory = httpContext.RequestServices.GetRequiredService<ICategoryService>().GetCategoryType(2),
		GetKeyedServiceCategory = httpContext.RequestServices.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2),
		GetRequiredKeyedServiceCategory = httpContext.RequestServices.GetRequiredKeyedService<ICategoryStorageService>("computers").Types.SingleOrDefault(c => c.Id == 2)
	};
});

Middleware

With middleware, you'll have to inject it as a parameter into the InvokeAsync method:

// ServiceProviderMiddleware.cs
// ServiceProviderMiddleware.cs
public class ServiceProviderMiddleware
{
	private readonly RequestDelegate _next;

	public ServiceProviderMiddleware(
		RequestDelegate next
	)
	{
		_next = next;
	}

	public async Task InvokeAsync(
		HttpContext httpContext,
		IServiceProvider serviceProvider
	)
	{
		httpContext.Items.Add("GetService", serviceProvider.GetService<ICategoryService>()?.GetCategoryType(2));
		httpContext.Items.Add("GetRequiredService", serviceProvider.GetRequiredService<ICategoryService>().GetCategoryType(2));
		httpContext.Items.Add("GetKeyedService", serviceProvider.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2));
		httpContext.Items.Add("GetRequiredKeyedService", serviceProvider.GetRequiredKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2));

		await _next(httpContext);
	}
}

The InvokeAsync method already has a HttpContext type as a parameter, so you can use that to get the IServiceProvider instance by calling HttpContext.RequestServices:

// ServiceProviderMiddleware.cs
public class ServiceProviderMiddleware
{
	private readonly RequestDelegate _next;

	public ServiceProviderMiddleware(
		RequestDelegate next
	)
	{
		_next = next;
	}

	public async Task InvokeAsync(
		HttpContext httpContext
	)
	{
		httpContext.Items.Add("GetService", httpContext.RequestServices.GetService<ICategoryService>()?.GetCategoryType(2));
		httpContext.Items.Add("GetRequiredService", httpContext.RequestServices.GetRequiredService<ICategoryService>().GetCategoryType(2));
		httpContext.Items.Add("GetKeyedService", httpContext.RequestServices.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2));
		httpContext.Items.Add("GetRequiredKeyedService", httpContext.RequestServices.GetRequiredKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2));

		await _next(httpContext);
	}
}

Primary constructors

It's also possible to inject the IServiceProvider instance with primary constructors:

// CategoryPrimaryService.cs
public class CategoryPrimaryService(IServiceProvider serviceProvider) 
{
	public CategoryTypeDto? GetService() => serviceProvider.GetService<ICategoryService>()?.GetCategoryType(2);

	public CategoryTypeDto? GetRequiredService() => serviceProvider.GetRequiredService<ICategoryService>()?.GetCategoryType(2);

	public CategoryTypeDto? GetKeyedService() => serviceProvider.GetKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2);

	public CategoryTypeDto? GetRequiredKeyedService() => serviceProvider.GetRequiredKeyedService<ICategoryStorageService>("computers")?.Types.SingleOrDefault(c => c.Id == 2);
}

When the web application builds

Once the web application builds, services can be resolved before the web application runs.

The WebApplication type contains a Services property which has the IServiceProvider type. From there, you can use the GetService, GetRequiredService, GetKeyedService and GetRequiredKeyedService.

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<ICategorySingletonService, CategorySingletonService>();
builder.Services.AddKeyedSingleton<ICategoryStorageService, CategoryComputersStorageService>("computers");

var app = builder.Build();

// Get services on start up
var categorySingletonService = app.Services.GetRequiredService<ICategorySingletonService>();
var categoryComputersStorageService = app.Services.GetRequiredKeyedService<ICategoryStorageService>("computers");

app.Run();

You can only resolve singleton and transient service lifetime instances directly with the WebApplication type. If you need to resolve scoped service lifetime, you would need to resolve the IServiceScopeFactory instance and then call either the CreateScope or CreateAsyncScope methods and resolve the service from the newly created scope:

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<ICategorySingletonService, CategorySingletonService>();
builder.Services.AddScoped<ICategoryService, CategoryService>();
builder.Services.AddKeyedSingleton<ICategoryStorageService, CategoryComputersStorageService>("computers");

var app = builder.Build();

// Get services on start up
var categorySingletonService = app.Services.GetRequiredService<ICategorySingletonService>();
var categoryComputersStorageService = app.Services.GetRequiredKeyedService<ICategoryStorageService>("computers");
var serviceScopeFactory = app.Services.GetRequiredService<IServiceScopeFactory>();

using (var scope = serviceScopeFactory.CreateScope())
{
    var categoryService = scope.ServiceProvider.GetRequiredService<ICategoryService>();
}

app.Run();

Watch the video

Watch the video where we show you how to use the IServiceProvider in many different areas to resolve a service.

And if you want to try out using the IServiceProvider type, you can download the code example which gives you examples on how to use it in ASP.NET Core.

When should you use IServiceProvider?

IServiceProvider is good if you don't know whether the instance will be registered. This might be the case if an instance is only registered if a certain feature flag is enabled.

It's also good if you have many dependencies to resolve in a class. It might be better to inject the IServiceProvider instance and then resolve them when you want to use them.

But your code would be more readable if you inject the services directly with parameters. So unless you have a reason to use IServiceProvider type, it's recommended to specify each of the services as parameters.