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 的约定)。并且还处理多个 类 注册相同的接口。
我们有一个 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 的约定)。并且还处理多个 类 注册相同的接口。