5

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

我看到这样的例子,我可以看到其中的相关性,因为 IHttpController 不继承 IDisposable,并且 IHttpController 的实现不保证它自己的处置逻辑。

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

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

公共 IHttpController 创建(
    HttpRequestMessage 请求,
    HttpControllerDescriptor 控制器描述符,
    类型控制器类型)
{
    if (controllerType == typeof(RootController))
    {
        var 一次性查询 = 新的 DisposableStatusQuery();
        request.RegisterForDispose(disposableQuery);
        返回新的 RootController(disposableQuery);
    }
    返回空值;
}

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

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

我什么时候真正需要使用 HttpRequestMessage.RegisterForDispose?

4

4 回答 4

1

我发现它对一种场景很有用:用于自定义 ActionFilter。

因为属性被缓存/重用,属性中的项目不应该依赖于控制器来处理(据我的理解 - 并且可能有警告)......所以为了创建一个自定义属性而不是绑定到特定的控制器类型/实现,您可以使用此技术来清理您的东西。就我而言,它用于环境 DbContextScope 属性。

于 2015-04-09T14:15:57.690 回答
1

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

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

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

于 2015-04-09T15:57:27.510 回答
0

有人可能想在请求的生命周期中挂钩代码,该请求 (1) 与控制器无关,并且 (2) 不子类化请求类型。

例如,我会想象这种代码的惯用形式采用扩展方法的形式HttpRequestMessage。如果代码分配了可支配资源,则需要将处置代码与某物挂钩。我对 ASP.NET 管道的各种扩展点不太熟悉,但我认为挂钩代码只是为了在请求处理阶段结束时处理资源很常见,足以证明可使用资源的专用注册机制(如与更普遍地订阅要执行的代码相反)。

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

希望这可以帮助。

于 2014-10-15T09:49:38.247 回答
0

我将 RegisterForDispose 与 DI 容器一起使用。根据博客文章,我已经实现在每次请求后处理容器(嵌套容器),以便清除我创建的所有对象。

于 2012-12-18T04:55:13.993 回答