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?
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.
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.
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.
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.GetRequiredService<MyService>();
[FromServices]
parameters in methods (i.e. it only checks constructor dependencies)services.AddSingleton(typeof(MyServiceWithGeneric<>));
services.AddSingleton<MyService>(provider =>
{
var nestedService = provider.GetRequiredService<MyNestedService>();
return new MyService(nestedService);
});
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