简单的注入器:RegisterWebApiController无法抑制DisposableTransientComponent警告

时间:2018-08-29 16:50:48

标签: c# asp.net-web-api simple-injector

我可能是在简化或误解,所以如果这是一个愚蠢的问题,我想提前道歉。 :)

根据我所看到的文档和代码,我的理解是,当使用简单注入器(在RegisterWebApiController上调用4.3.0时,应禁止所有类的“一次性瞬态组件”警告类型为ApiController

话虽如此,下面的代码引发了无效的配置错误

public class SimpleInjectorConfiguration
{
    public static void Configure(
        Container container, HttpConfiguration configuration)
    {
        container.RegisterWebApiControllers(
            configuration, Assembly.GetAssembly(typeof(TestController)));

        //Register the other required classes
    }
}
  

配置无效。报告了以下诊断警告:   -[Disposable Transient Component]已注册为瞬态,但实现了IDisposable。

实际上没有一个控制器会覆盖IDisposable方法,并且据我所知,下面的代码片段(取自最新的Simple Injector source)应该被成功调用:

registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
    justification:
        "Web API registers controllers for disposal when the request ends during the " +
        "call to ApiController.ExecuteAsync.");

这种混淆来自于这样一个事实,当我使用以下代码修改Configure方法时,它确实可以成功消除警告(即,可以正常工作)。

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
}

更令人困惑的是,我们在许多其他项目中使用了Simple Injector,警告抑制似乎在所有这些项目中均能正常工作,但这就是为什么我认为这是某种配置问题。我尝试过比较这些项目以发现有什么不同,但是很遗憾,我还没有提出任何建议。

TestController代码定义为

[RoutePrefix("api/Test")]
public class TestController : ApiController
{
    public IHttpActionResult GetTestString()
    {
        return Ok("Test String from Test Controller");
    }
}

任何人都遇到过这种情况,或者可以弄清楚为什么会发生这种情况?谢谢!


更新

由于下面的史蒂文(Steven)提供的信息,我设法弄清了这个问题是由于SimpleInjector库之间看起来不一致的原因。

SimpleInjector4.3.0上,而SimpleInjector.Integration.WebApi3.1.0上。将SimpleInjector.Integration.WebApi升级到4.3.0就可以了。

1 个答案:

答案 0 :(得分:1)

发生这种情况的最可能原因是因为您的Web API控制器同时实现了IHttpControllerIDisposable,但没有继承自ApiController

Web API的ApiController基类在RegisterForDispose方法的内部 中注册自己以供​​处置(通过调用SendAsync)。这样可以确保在请求结束时将处置控制器。

这就是为什么Simple Injector在从ApiController继承的控制器上抑制诊断警告的原因; Web API将确保将它们丢弃。

由于要进行处置的注册发生在ApiController内部 中,这确实意味着仅实现IHttpController(但不继承自ApiController的控制器)将永远不要处置。这就是为什么Simple Injector仅在ApiController导数的情况下禁止显示此警告的原因。

因此,您应该从不禁止在您的Web API控制器上抑制此诊断警告,而无需采取其他保证保证您的控制器被处置的前提。

如果控制器没有有意义的处理逻辑,则应从控制器中删除IDisposable接口。这消除了问题。控制器很少需要处理逻辑,因为您通常应将此逻辑提取到其他服务中。控制器通常不应依赖于它自己创建的资源。

但是,如果该控制器确实需要处置,则可以覆盖其注册以成为Lifestyle.Scoped。这样可以确保类型由Simple Injector处置:

container.RegisterWebApiControllers(         配置,Assembly.GetAssembly(typeof(TestController)));

container.Options.AllowOverridingRegistrations = true;
container.Register<MySpecialController>(Lifestyle.Scoped);
container.Options.AllowOverridingRegistrations = false;

或者,您可以仅在该特定控制器上取消诊断警告,并烹饪一个特殊的代表以确保对其进行处置:

container.GetRegistration(typeof(MySpecialController)).Registration
    .SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent, 
        "We dispose manually.");

container.RegisterInitializer<MySpecialController>(c =>
    Lifestyle.Scoped.GetCurrentScope(container).RegisterForDisposal(c));