Nancy IoC 每个请求自动注册

Nancy IoC per request auto registration

我们有一个 ASP.NET REST 服务用 Nancy(和 TinyIoc)实现,它与一个相当大的遗留应用程序接口。我们希望 t运行sition 完全依赖注入。目前,我们的大多数模块直接实例化控制器,并使用 NancyContext Context 属性 获取包含请求信息的上下文 class。像这样:

public FooModule(ILegacyService legacyService) {
    Get["/"] = parameters => new FooController(new RequestContext(Context), legacyService).GetFoo();
}

我们想直接在模块中注入控制器,并让 super-duper-happy-path 处理所有事情:)

我们的问题都源于我们需要来自NancyContext的信息。 url、headers 等。所以我们尝试了各种方法来实现依赖注入必杀技。

尝试注入控制器失败,因为它们是在应用程序范围内实例化的,因此对 RequestContext 的任何依赖都不会具有当前上下文信息。即使在 ConfigureRequestContainer 中注册 RequestContext 也没有波及所有受抚养人,他们会保留对过时 RequestContext.

的引用

我们已经尝试 属性 使用 IRequestStartup 注入上下文,这似乎是成功的,直到我们 运行 陷入并发问题。不同线程中的同时请求将覆盖应用程序范围 RequestContext

我们发现我们可以在 ConfigureRequestContainer 中调用 container.AutoRegister(),但这导致了严重的延迟,因为我们拥有的类型数量需要几秒钟的时间进行注册。

ConfigureApplicationContainer 中使用 AsPerRequestSingleton() 似乎它将注册一次,然后根据请求实例化,但似乎没有办法让自动注册遵守这一点。

看来我们需要手动注册所有类型,并手动更新此配置。是这样吗?我们真的希望每个请求生命周期都有某种类型的自动注册。

我创建了一个小型测试项目 (https://github.com/Rassi/NancyIocTest),我在其中尝试了其中的一些解决方案。

使用 DefaultNancyAspNetBootstrapper,您可以像这样创建自己的自动注册:

public class Bootstrapper : DefaultNancyAspNetBootstrapper
{
    protected override void ConfigureApplicationContainer(TinyIoCContainer container)
    {
        var assemblyClasses = Assembly.GetExecutingAssembly().GetTypes().Where(type => type.IsClass);
        foreach (var assemblyClass in assemblyClasses)
        {
            var interfaces = assemblyClass.GetInterfaces();
            if (interfaces.Count() == 1)
            {
                container.Register(interfaces[0], assemblyClass).AsPerRequestSingleton();
            }
        }
    }

然后根据请求实例化所有内容,您可以使用 RequestStartup():

注入上下文信息
    protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
    {
        base.RequestStartup(container, pipelines, context);
        var requestUrl = container.Resolve<IRequestUrl>();
        requestUrl.Context = context;
    }
}

这是一个简单的概念验证,它将找到实现一个接口的 类,并将其注册到该接口。可能应该处理几个问题,例如:注册 类 实现多个接口(可能使用将 Name 注册到 IName 的约定)。并且还处理多个 类 注册相同的接口。