NancyFx 配置请求容器
NancyFx ConfigureRequestContainer
我想弄清楚 NancyFx 请求容器是如何工作的,所以我创建了一个小测试项目。
我创建了这个界面
public interface INancyContextWrapper
{
NancyContext Context { get; }
}
有了这个实现
public class NancyContextWrapper : INancyContextWrapper
{
public NancyContext Context { get; private set; }
public NancyContextWrapper(NancyContext context)
{
Context = context;
}
}
然后在引导程序中我这样注册它
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
base.ConfigureRequestContainer(container, context);
container.Register<INancyContextWrapper>(new NancyContextWrapper(context));
}
我在 class 中使用此上下文包装器,它除了 return 将请求 url 作为字符串之外什么都不做。
public interface IUrlString
{
string Resolve();
}
public class UrlString : IUrlString
{
private readonly INancyContextWrapper _context;
public UrlString(INancyContextWrapper context)
{
_context = context;
}
public string Resolve()
{
return _context.Context.Request.Url.ToString();
}
}
最后在模块中使用它
public class RootModule : NancyModule
{
public RootModule(IUrlString urlString)
{
Get["/"] = _ => urlString.Resolve();
}
}
当我这样做时,请求总是空的。现在我或多或少可以弄清楚,由于 IUrlString
没有在请求容器配置中配置,TinyIoc 在发出任何请求之前在应用程序启动时解析 INancyContextWrapper
,并且 TinyIoc 不会重新注册依赖项依赖关系图依赖于请求容器配置中配置的内容。
我的问题是使用 ConfigureRequestContainer 的最佳实践是什么?我是否必须在请求容器配置中注册以任何方式显式依赖 NancyContext 的所有内容?这很快就会变得臃肿且难以维护。我喜欢 TinyIoc 进行程序集扫描的方式,所以不得不这样做有点挫折。
假设上面的示例只是您实际想要的东西的简化 - 即出于某种目的在请求生命周期内携带 nancy 上下文的东西,您最好根本不使用引导程序,因为它取决于使用的 IoC 容器。
建议:
将包装器的实现更改为不使用 ctor,而是使用 属性 setter(您始终可以编写代码,以便仅设置 属性一次):
public interface INancyContextWrapper
{
NancyContext Context { get; set; }
}
public class NancyContextWrapper : INancyContextWrapper
{
private NancyContext _context;
public NancyContext Context
{
get {return _context;}
set {_context = value;} //do something here if you want to prevent repeated sets
}
}
不直接使用容器和引导程序,而是使用 IRegistration 实现(这些由 nancy 使用,并且与容器无关)
public class NancyContextWrapperRegistrations : IRegistrations
{
public IEnumerable<TypeRegistration> TypeRegistrations
{
get
{
return new[]
{
new TypeRegistration(typeof(INancyContextWrapper), typeof(NancyContextWrapper), Lifetime.PerRequest),
new TypeRegistration(typeof(IUrlString .... per request
};
// or you can use AssemblyTypeScanner, etc here to find
}
//make the other 2 interface properties to return null
}
}
使用 IRequestStartup 任务(这些也是 nancy 自动发现的)设置上下文
public class PrepareNancyContextWrapper : IRequestStartup
{
private readonly INancyContextWrapper _nancyContext;
public PrepareNancyContextWrapper(INancyContextWrapper nancyContext)
{
_nancyContext = nancyContext;
}
public void Initialize(IPipelines piepeLinse, NancyContext context)
{
_nancyContext.Context = context;
}
}
虽然上面看起来有些矫枉过正,但它是以独立于 IoC 的方式组织类型注册的非常好的方式(即,如果你用其他东西替换 TinyIoC,你不需要接触引导程序等)
此外,这是控制请求(或者如果你想要 - 应用程序)启动期间发生的事情的好方法,w/o 覆盖引导程序中的任何内容,它可以与任何 bootstrapper/container 一起工作你决定去。
我想弄清楚 NancyFx 请求容器是如何工作的,所以我创建了一个小测试项目。
我创建了这个界面
public interface INancyContextWrapper
{
NancyContext Context { get; }
}
有了这个实现
public class NancyContextWrapper : INancyContextWrapper
{
public NancyContext Context { get; private set; }
public NancyContextWrapper(NancyContext context)
{
Context = context;
}
}
然后在引导程序中我这样注册它
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
base.ConfigureRequestContainer(container, context);
container.Register<INancyContextWrapper>(new NancyContextWrapper(context));
}
我在 class 中使用此上下文包装器,它除了 return 将请求 url 作为字符串之外什么都不做。
public interface IUrlString
{
string Resolve();
}
public class UrlString : IUrlString
{
private readonly INancyContextWrapper _context;
public UrlString(INancyContextWrapper context)
{
_context = context;
}
public string Resolve()
{
return _context.Context.Request.Url.ToString();
}
}
最后在模块中使用它
public class RootModule : NancyModule
{
public RootModule(IUrlString urlString)
{
Get["/"] = _ => urlString.Resolve();
}
}
当我这样做时,请求总是空的。现在我或多或少可以弄清楚,由于 IUrlString
没有在请求容器配置中配置,TinyIoc 在发出任何请求之前在应用程序启动时解析 INancyContextWrapper
,并且 TinyIoc 不会重新注册依赖项依赖关系图依赖于请求容器配置中配置的内容。
我的问题是使用 ConfigureRequestContainer 的最佳实践是什么?我是否必须在请求容器配置中注册以任何方式显式依赖 NancyContext 的所有内容?这很快就会变得臃肿且难以维护。我喜欢 TinyIoc 进行程序集扫描的方式,所以不得不这样做有点挫折。
假设上面的示例只是您实际想要的东西的简化 - 即出于某种目的在请求生命周期内携带 nancy 上下文的东西,您最好根本不使用引导程序,因为它取决于使用的 IoC 容器。
建议:
将包装器的实现更改为不使用 ctor,而是使用 属性 setter(您始终可以编写代码,以便仅设置 属性一次):
public interface INancyContextWrapper
{
NancyContext Context { get; set; }
}
public class NancyContextWrapper : INancyContextWrapper
{
private NancyContext _context;
public NancyContext Context
{
get {return _context;}
set {_context = value;} //do something here if you want to prevent repeated sets
}
}
不直接使用容器和引导程序,而是使用 IRegistration 实现(这些由 nancy 使用,并且与容器无关)
public class NancyContextWrapperRegistrations : IRegistrations
{
public IEnumerable<TypeRegistration> TypeRegistrations
{
get
{
return new[]
{
new TypeRegistration(typeof(INancyContextWrapper), typeof(NancyContextWrapper), Lifetime.PerRequest),
new TypeRegistration(typeof(IUrlString .... per request
};
// or you can use AssemblyTypeScanner, etc here to find
}
//make the other 2 interface properties to return null
}
}
使用 IRequestStartup 任务(这些也是 nancy 自动发现的)设置上下文
public class PrepareNancyContextWrapper : IRequestStartup
{
private readonly INancyContextWrapper _nancyContext;
public PrepareNancyContextWrapper(INancyContextWrapper nancyContext)
{
_nancyContext = nancyContext;
}
public void Initialize(IPipelines piepeLinse, NancyContext context)
{
_nancyContext.Context = context;
}
}
虽然上面看起来有些矫枉过正,但它是以独立于 IoC 的方式组织类型注册的非常好的方式(即,如果你用其他东西替换 TinyIoC,你不需要接触引导程序等)
此外,这是控制请求(或者如果你想要 - 应用程序)启动期间发生的事情的好方法,w/o 覆盖引导程序中的任何内容,它可以与任何 bootstrapper/container 一起工作你决定去。