如何使用Autofac由南希创造了一个孩子一生的范围,以解决例如每个请求的依赖关系类型 [英] How to use Autofac to resolve instance per request dependencies for types in a child lifetime scope created by Nancy

查看:295
本文介绍了如何使用Autofac由南希创造了一个孩子一生的范围,以解决例如每个请求的依赖关系类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


我们在Windows服务,自我,以揭露有关的应用程序的操作仪器主办南希端点承载多个应用程序。



我们使用Autofac作为我们的国际奥委会。一些库注册成由所有应用程序共享一个核心DLL根容器;那么这个容器传递给南希与使用从 Nancy.Autofac.Bootstrapper



派生的引导程序及其容器

我们的发现是,当由南希接收的网页请求时,它解决了一个请求,从根容器的存储库,这导致内存收集的非垃圾被消耗的IDisposable S作为根容器不出去范围(它具有Windows服务的生命周期)。这导致了泄漏内存的服务。



然后,我们切换到我们增加了使用存储库注册的模型 InstancePerRequest 在我们南希引导程序的重写 ConfigureRequestContainer()方法:



<预类=郎-CS prettyprint-覆盖> 保护覆盖无效ConfigureRequestContainer(ILifetimeScope容器,NancyContext上下文)
{
base.ConfigureRequestContainer(集装箱,背景);
PerRequestContainerBuilder()更新(container.ComponentRegistry)。
}

私有静态ContainerBuilder PerRequestContainerBuilder()
{
变种建设者=新ContainerBuilder();

//依赖于库
builder.RegisterType&所述; SystemDateTimeProvider方式>()InstancePerRequest()为< IDateTimeProvider>();

//库
builder.RegisterType&所述; BookmarkRepository方式>()InstancePerRequest()为< IBookmarkRepository>();

返回建设者;
}

我们还覆盖 CreateRequestContainer()方法来创建与标签 MatchingScopeLifetimeTags.RequestLifetimeScopeTag 请求容器。



<预类=郎-CS prettyprint-覆盖> 保护覆盖ILifetimeScope CreateRequestContainer(NancyContext上下文)
{
返回ApplicationContainer.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
}

这似乎已经解决了 IDisposable的<问题/ code>不是布置 - 子请求容器被布置在web请求管道和对象的由它解决了端也设置并最终垃圾回收



我们的问题是,这似乎是漏了库的实现细节到服务,我们不仅要登记在库ConfigureRequestContainer(),而且任何由库所需的其他对象,也就是说,如果我们想改变,我们必须走依赖链用它来注册每个服务所需的对象存储库的实现 - 这似乎是错误的。



有没有一种方法我们可以得到Autofac解决了库支持的对象了根容器,但保留web请求容器的范围内的注册信息?或者是有办法来自动创建时,现有的登记从根容器复制到子容器?


解决方案

Autofac应自动解决从父寿命实例。如果您在使用配置您注册 InstancePerRequest ,Autofac会用特殊标记一辈子注册这些服务, MatchingScopeLifetimeTags.RequestLifetimeScopeTag ,所以它可以在正确的范围后得到解决。



这意味着,有没有必要使用南希引导程序的 ConfigureRequestContainer 方法来做请求范围的注册。你已经做到了!只要南希创建使用 InstancePerRequest 使用相同的标记(这是的默认做南希1.1)的,服务应该被正确解析



例如:

 公共类启动
{
公共无效配置(IAppBuilder应用程序)
{
变种建设者=新ContainerBuilder();

//使用InstancePerRequest ...

变种容器是否在请求范围内注册= builder.Build();

//传递给引导程序
VAR引导程序=新MyAwesomeNancyBootstrapper(容器)的预建的容器中;

app.UseNancy(选项=> options.Bootstrapper =引导程序);
}
}





 公共类MyAwesomeNancyBootstrapper:AutofacNancyBootstrapper 
{
私人只读ILifetimeScope _lifetimeScope;

公共MyAwesomeNancyBootstrapper(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
}

保护覆盖ILifetimeScope GetApplicationContainer()
{
返回_lifetimeScope; //告诉南希,你已经有了一个集装箱整装待发;)
}
}

此设置应该足够(南希1.1。在早期版本中,你也必须重写 CreateRequestContainer 方法并传递请求生命周期标签创建请求生命周期时, 。范围内)



修改:我放在一起的例子为你的 https://github.com/khellang/Nancy.AutofacExample


We have several applications hosted in Windows services that self host a Nancy endpoint in order to expose instrumentation about the operation of the applications.

We use Autofac as our IOC. Several repositories are registered into the root container in a core DLL shared by all applications; this container is then passed to Nancy as its container using a bootstrapper derived from the Nancy.Autofac.Bootstrapper.

What we found was that when a web request is received by Nancy it resolves a request for a repository from the root container and this led to memory being consumed by non-garbage collected IDisposables as the root container does not go out of scope (it has the lifetime of the windows service). This led to the services "leaking" memory.

We then switched to a model where we added registrations for the repositories using InstancePerRequest in the overridden ConfigureRequestContainer() method in our Nancy bootstrapper:

protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context)
{
    base.ConfigureRequestContainer(container, context);
    PerRequestContainerBuilder().Update(container.ComponentRegistry);
}

private static ContainerBuilder PerRequestContainerBuilder()
{
    var builder = new ContainerBuilder();

    // Dependency for repository
    builder.RegisterType<SystemDateTimeProvider>().InstancePerRequest().As<IDateTimeProvider>();

    // Repository
    builder.RegisterType<BookmarkRepository>().InstancePerRequest().As<IBookmarkRepository>();

    return builder;
}

We also override the CreateRequestContainer() method to create the request container with the tag MatchingScopeLifetimeTags.RequestLifetimeScopeTag.

protected override ILifetimeScope CreateRequestContainer(NancyContext context)
{
     return ApplicationContainer.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
}

This appears to have solved the problem of IDisposables not being disposed - the child request container is disposed at the end of the web request pipeline and objects resolved by it are also disposed and eventually garbage collected.

Our problem is that this seems to be leaking the implementation details of the repositories into the services as we have to not only register the repository in ConfigureRequestContainer() but also any other objects required by the repository, i.e. if we want to change the implementation of a repository we have to "walk the dependency chain" to register required objects in each service using it - this seems wrong.

Is there a way we can get Autofac to resolve supporting objects for the repositories out of the root container but keep the registration information within the scope of the web request container? Or is there a way to automatically copy existing registrations from the root container into the child container when it is created?

解决方案

Autofac should automatically resolve instances from "parent" lifetimes. If you configure your registrations using InstancePerRequest, Autofac will register these services with a special lifetime tag, MatchingScopeLifetimeTags.RequestLifetimeScopeTag, so it can be resolved in the correct scope later.

This means that there's no need to use the Nancy bootstrapper's ConfigureRequestContainer method to do request-scoped registrations. You've already done it! As long as Nancy creates the request lifetime using the same tag used in InstancePerRequest (this is done by default as of Nancy 1.1), the services should be resolved correctly.

Example:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var builder = new ContainerBuilder();

        // Do request-scoped registrations using InstancePerRequest...

        var container = builder.Build();

        // Pass the pre-built container to the bootstrapper
        var bootstrapper = new MyAwesomeNancyBootstrapper(container);

        app.UseNancy(options => options.Bootstrapper = bootstrapper);
    }
}

public class MyAwesomeNancyBootstrapper : AutofacNancyBootstrapper
{
    private readonly ILifetimeScope _lifetimeScope;

    public MyAwesomeNancyBootstrapper(ILifetimeScope lifetimeScope)
    {
        _lifetimeScope = lifetimeScope;
    }

    protected override ILifetimeScope GetApplicationContainer()
    {
        return _lifetimeScope; // Tell Nancy you've got a container ready to go ;)
    }
}

This setup should be enough (As of Nancy 1.1. In earlier versions you have to also override the CreateRequestContainer method and pass the request lifetime tag when creating the request lifetime scope).

EDIT: I put together an example for you at https://github.com/khellang/Nancy.AutofacExample

这篇关于如何使用Autofac由南希创造了一个孩子一生的范围,以解决例如每个请求的依赖关系类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆