何时使用Request.RegisterForDispose?

时间:2012-12-17 02:03:22

标签: asp.net asp.net-mvc asp.net-web-api

对于ASP.NET Web API,我一直致力于自己的IHttpControllerActivator实现,并且想知道何时(或为什么?)使用HttpRequestMessage扩展方法“{{1} }”。

我看到这样的例子,我可以看到它的相关性,因为IHttpController没有继承IDisposable,而IHttpController的实现并不保证它自己的dispose逻辑。

public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
    var controller = (IHttpController) _kernel.Get(controllerType);
    request.RegisterForDispose( new Release(()=> _kernel.Release(controller)));
    return controller;
}

然后我看到这样的事情并开始怀疑:

public IHttpController Create(
    HttpRequestMessage request,
    HttpControllerDescriptor controllerDescriptor,
    Type controllerType)
{
    if (controllerType == typeof(RootController))
    {
        var disposableQuery = new DisposableStatusQuery();
        request.RegisterForDispose(disposableQuery);
        return new RootController(disposableQuery);
    }
    return null;
}

在这种情况下,RootController在这里没有注册处理,大概是因为它是一个ApiController或MVC控制器? - 因此会自行处理。

DisposableStatusQuery的实例已注册处理,因为它是一次性对象,但为什么控制器不能处理实例本身? RootController具有disposableQuery(或者更确切地说,它的接口或抽象基础)的知识,因此会知道它是一次性的。

我什么时候需要才能使用HttpRequestMessage.RegisterForDispose?

4 个答案:

答案 0 :(得分:1)

我发现一个场景对于自定义ActionFilter非常有用。

因为属性被缓存/重新使用,属性中的项目不应该依赖于控制器被处理(根据我的理解 - 可能还有警告)......所以为了创建自定义属性不是与特定的控制器类型/实现相关联,您可以使用此技术来清理您的东西。在我的例子中,它是环境DbContextScope属性。

答案 1 :(得分:1)

RegisterForDispose这是一个在处理请求时将被调用的钩子。这通常与依赖注入容器的“一些”一起使用。

例如,默认情况下,某些容器(如Castle.Windsor)将跟踪他们解析的所有依赖项。这是根据Windsor ReleasePolicy LifecycledComponentsReleasePolicy的说法,它声明它将跟踪创建的所有组件。换句话说,如果容器仍然跟踪组件,则垃圾收集器将无法清理。这将导致内存泄漏。

因此,例如,当您定义自己的IHttpControllerActivator以将其与依赖注入容器一起使用时,它是为了解析具体控制器及其所有依赖项。在请求结束时,您需要通过容器释放所有创建的依赖项,否则您将以大内存泄漏结束。您有机会使用RegisterForDispose

进行此操作

答案 2 :(得分:0)

我使用RegisterForDispose和DI容器。基于Blog post我已实现在每个请求之后处理容器(嵌套容器),以便它清除我创建的所有对象。

答案 3 :(得分:0)

有人可能希望在代码的生命周期中挂钩代码,(1)与控制器关系不大,(2)不会对请求类型进行子类化。

我认为这种代码的惯用形式在HttpRequestMessage上采用了扩展方法的形式。如果代码分配了可支配资源,则需要将处理代码挂钩到某些东西。我不太熟悉ASP.NET管道的各种扩展点,但我认为在请求处理阶段结束时仅仅为了处理资源而挂钩代码就足以证明一次性资源的专用注册机制(如反对更普遍订阅要执行的代码。)

既然你问,我在this sample找到了一个很好的例子。这里,实体框架上下文被设置为请求的属性,必须正确处理。虽然此属性旨在供控制器使用,但它们并不特定于任何控制器或控制器超类,因此在我看来这是一个非常明智的设计选择。如果您对此感到好奇,这是因为这些请求是“OData批处理请求”,并且将在每个请求的生命周期内多次调用控制器操作(每个“操作”一次)。某些操作被分组为原子“变更集”,必须包含在比控制器更高级别的事务中(使用专用机制:ODataBatchHandler,这样控制器本身就不会忘记这一点)。因此,单独的控制器是不够的,因为在这种情况下,人们不能让它们自己处理上下文。

希望这有帮助。