I may be simplifying or misunderstanding things, so I'd like to apologise in advance if this is a really dumb question. :)
Based on the documentation and code I've seen, my understanding is that when calling RegisterWebApiController
with Simple Injector (on 4.3.0
), the "Disposable Transient Component" warnings should be suppressed for all classes that are of type ApiController
.
Having said that, the below code is throwing an invalid configuration error
public class SimpleInjectorConfiguration
{
public static void Configure(
Container container, HttpConfiguration configuration)
{
container.RegisterWebApiControllers(
configuration, Assembly.GetAssembly(typeof(TestController)));
//Register the other required classes
}
}
The configuration is invalid. The following diagnostic warnings were reported: -[Disposable Transient Component] is registered as transient, but implements IDisposable.
None of the controllers actually override the IDisposable
method, and from what I can debug, the below code fragment (taken from the latest Simple Injector
source) should be getting called successfully:
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
justification:
"Web API registers controllers for disposal when the request ends during the " +
"call to ApiController.ExecuteAsync.");
The confusion comes from the fact that when I modify the Configure
method with the below code, it does successfully suppress the warnings (i.e. It works).
public static void Configure(
Container container, HttpConfiguration configuration)
{
container.RegisterWebApiControllers(
configuration, Assembly.GetAssembly(typeof(TestController)));
foreach (var component in container.GetCurrentRegistrations())
{
component.Registration.SuppressDiagnosticWarning(
DiagnosticType.DisposableTransientComponent,
"Web API registers controllers for disposal when the request ends during " +
"the call to ApiController.ExecuteAsync.");
}
//Register the other required classes
}
To add to the confusion, we've used Simple Injector in a number of other projects and the warning suppression seems to work as intended in all of them but this which is why I'm thinking it's a configuration issue of some sort. I've tried comparing the projects to find what's different, but unfortunately I'm not coming up with anything as yet.
The TestController
code is defined as
[RoutePrefix("api/Test")]
public class TestController : ApiController
{
public IHttpActionResult GetTestString()
{
return Ok("Test String from Test Controller");
}
}
Anyone ever encountered this or can shed some light as to why this may be happening? Thank you!
Thanks to the information provided by Steven below, I managed to figure out that the issue was because of what looks like inconsistencies between SimpleInjector
libraries.
SimpleInjector
was on 4.3.0
, while SimpleInjector.Integration.WebApi
was on 3.1.0
. Upgrading SimpleInjector.Integration.WebApi
to 4.3.0
did the trick.
The most likely reason this is happening is because your Web API Controller implements both IHttpController
and IDisposable
, but does not inherit from ApiController
.
Web API's ApiController
base class registers itself for disposal (by calling RegisterForDispose
) inside its SendAsync
method. This ensures that the controller will get disposed when the request ends.
This is why Simple Injector suppresses the diagnostic warning on controllers that inherit from ApiController
; Web API will ensure they will get disposed.
Since the registration for disposal happens inside the ApiController
, it does mean that a controller that simply implements IHttpController
(but without inheriting from ApiController
) will never get disposed. This is why Simple Injector only suppresses this warning in the case of ApiController
derivatives.
Because of this, you should never suppress this diagnostic warning on your Web API controllers without taking other prepercusions that garantee your controller is disposed.
If your controller has no meaningful dispose logic, you should remove the IDisposable
interface from the controller. This removes the problem. It should be rare for a controller to require dispose logic, because you should typically extract this to other services; controllers should typically not depend on resources that it creates itself.
If that controller, however, does require disposal, you can override its registration to become Lifestyle.Scoped
. This ensures the type is disposed by Simple Injector:
container.RegisterWebApiControllers( configuration, Assembly.GetAssembly(typeof(TestController)));
container.Options.AllowOverridingRegistrations = true;
container.Register<MySpecialController>(Lifestyle.Scoped);
container.Options.AllowOverridingRegistrations = false;
Alternatively, you can suppress the diagnostic warning, only on that specific controller, and cook a special delegate that ensures its disposal:
container.GetRegistration(typeof(MySpecialController)).Registration
.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
"We dispose manually.");
container.RegisterInitializer<MySpecialController>(c =>
Lifestyle.Scoped.GetCurrentScope(container).RegisterForDisposal(c));