In my Startup
class I use the ConfigureServices(IServiceCollection services)
method to set up my service container, using the built-in DI container from Microsoft.Extensions.DependencyInjection
.
I want to validate the dependency graph in an unit test to check that all of the services can be constructed, so that I can fix any services missing during unit testing instead of having the app crash at runtime. In previous projects I've used Simple Injector, which has a .Verify()
method for the container. But I haven't been able to find anything similar for ASP.NET Core.
Is there any built-in (or at least recommended) way of verifying that the entire dependency graph can be constructed?
(The dumbest way I can think of is something like this, but it will still fail because of the open generics that are injected by the framework itself):
startup.ConfigureServices(serviceCollection); var provider = serviceCollection.BuildServiceProvider(); foreach (var serviceDescriptor in serviceCollection) { provider.GetService(serviceDescriptor.ServiceType); }
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.
AddScoped(IServiceCollection, Type, Type) Adds a scoped service of the type specified in serviceType with an implementation of the type specified in implementationType to the specified IServiceCollection.
IoC Container (a.k.a. DI Container) is a framework for implementing automatic dependency injection. It manages object creation and it's life-time, and also injects dependencies to the class.
The recommended way to implement DI is, you should use DI containers. If you compose an application without a DI CONTAINER, it is like a POOR MAN'S DI . If you want to implement DI within your ASP.NET MVC application using a DI container, please do refer to Dependency Injection in ASP.NET MVC using Unity IoC Container.
A built-in DI container validation was added in ASP.NET Core 3 and it is enabled only in the Development
environment by default. If something is missing, the container throws a fatal exception on startup.
Keep in mind that controllers aren't created in the DI container by default, so a typical web app won't get much from this check until the controllers are registered in the DI:
public void ConfigureServices(IServiceCollection services) { services.AddControllers() .AddControllersAsServices(); }
To disable/customize the validation, add a IHostBuilder.UseDefaultServiceProvider
call:
public class Program { public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) //... .UseDefaultServiceProvider((context, options) => { options.ValidateOnBuild = false; });
This validation feature has several limitations, read more here: https://andrewlock.net/new-in-asp-net-core-3-service-provider-validation/
Actually, I just used the example from your question with a few modifications and it worked pretty well for me. The theory behind filtering by classes in my namespace is that those will end up asking for everything else I care about.
My test looked a lot like this:
[Test or Fact or Whatever] public void AllDependenciesPresentAndAccountedFor() { // Arrange var startup = new Startup(); // Act startup.ConfigureServices(serviceCollection); // Assert var exceptions = new List<InvalidOperationException>(); var provider = serviceCollection.BuildServiceProvider(); foreach (var serviceDescriptor in services) { var serviceType = serviceDescriptor.ServiceType; if (serviceType.Namespace.StartsWith("my.namespace.here")) { try { provider.GetService(serviceType); } catch (InvalidOperationException e) { exceptions.Add(e); } } } if (exceptions.Any()) { throw new AggregateException("Some services are missing", exceptions); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With