Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test all ASP.NET Core Controllers Dependency Injection is valid?

We occasionally have issues whereby someone adds some DI into a controller but forgets to add the relevant line into Startup.cs to set the scope of the object.

This does not prevent the application from starting, but rather, throws an exception when the relevent endpoint is hit.

Is there any way of programmatically checking all controllers are valid and preventing the application from starting otherwise?

Alternatively is there an easy way to write a catch-all automated test to check every controller can be instantiated using the specified DI in Startup.cs?

like image 262
Michael Parker Avatar asked Jun 11 '18 10:06

Michael Parker


People also ask

Does .NET Core have dependency injection?

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.

How do I run a test case in .NET Core?

To run test in Visual Studio, let us open Test Explorer from the Test → Window → Test Explorer menu option. And you can see that Visual Studio automatically detects the test. The name of the test consists of namespace.

What is difference between Addtransient and Addscoped and Addsingleton?

Singleton is a single instance for the lifetime of the application domain. Scoped is a single instance for the duration of the scoped request, which means per HTTP request in ASP.NET. Transient is a single instance per code request.


1 Answers

Summarised from https://andrewlock.net/new-in-asp-net-core-3-service-provider-validation/, please see link for more details.

As of ASP.NET 3.0 there is now a way to validate controller dependencies on build:

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddControllersAsServices(); // This part adds Controllers to DI

Program.cs:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            .UseDefaultServiceProvider((context, options) =>
            {
                options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
                // Validate DI on build
                options.ValidateOnBuild = true;
            });

Notes:

  • Service provider validation is only enabled in the Development environment by default.
  • Will not work for run-time ServiceProvider look ups (service locator pattern) e.g. _service = provider.GetRequiredService<MyService>();
  • Will not work for [FromServices] parameters in methods (i.e. it only checks constructor dependencies)
  • Will not work for 'open generics' e.g. services.AddSingleton(typeof(MyServiceWithGeneric<>));
  • Will not work for services registered with factory functions e.g.
    services.AddSingleton<MyService>(provider => 
    {
        var nestedService = provider.GetRequiredService<MyNestedService>();
        return new MyService(nestedService);
    });
like image 98
Michael Parker Avatar answered Sep 22 '22 15:09

Michael Parker