3

我想弄清楚 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));
}

我在一个除了将请求 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没有在请求容器配置中配置,因此 TinyIocINancyContextWrapper在发出任何请求之前在应用程序启动时解析,并且 TinyIoc 不会重新注册依赖关系图依赖于在请求容器配置。

我的问题是使用 ConfigureRequestContainer 的最佳做法是什么?我是否必须在请求容器配置中注册以任何方式显式依赖 NancyContext 的所有内容?这很快就会变得臃肿且难以维护。我喜欢 TinyIoc 进行程序集扫描的方式,所以不得不这样做有点受挫。

4

1 回答 1

4

假设上面的示例只是对您实际想要的内容的简化 - 即在请求生命周期内出于某种目的携带 nancy 上下文的东西,您最好不要使用引导程序,因为它取决于使用 IoC 容器。

建议:

将包装器的实现更改为不使用 ctor,而是使用属性设置器(您始终可以编写代码,以便属性只能设置一次)

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 替换为其他东西,则无需触摸引导程序等)

此外,这是控制请求(或者如果您想要 - 应用程序)启动期间发生的事情的非常好的方法,无需覆盖引导程序中的任何内容,并且它将与您决定使用的任何引导程序/容器一起使用。

于 2015-05-06T16:53:46.903 回答