【问题标题】:Resolving a dependency while supplying values for downstream dependencies在为下游依赖项提供值的同时解决依赖项
【发布时间】:2014-09-05 01:37:09
【问题描述】:

我在尝试将 Windsor 与 Web API 一起使用并将 HttpRequestMessage 注入控制器的下游依赖项时遇到了无穷无尽的问题。由于我已经在 Stackoverflow 上尝试了所有匹配的答案,我想以不同的方式提出这个问题:

在 Castle Windsor 中,如何在为 downstream 依赖项提供值的同时解析组件实例?也就是说,提供的值是被解析的组件所需要的组件所需要的。

对于上下文,我正在尝试注入 HttpRequestMessage 以便我可以使用它来解析请求上下文(主要是解析绝对 URL)。

编辑我还想指出,我目前没有对 Web Host / System.Web 的依赖,我不想改变它。

【问题讨论】:

  • 你能贴一些代码吗?通常状态不会被注入,所以使用抽象工厂来按值解析,或者数据只是通过方法传递(方法注入)。听起来你正在做的事情可能更复杂?
  • 想象SomethingController 依赖于SomethingServiceSomethingService 取决于 LinkGeneratorLinkGenerator 需要当前的 HttpRequestMessage 以便它可以生成绝对 URL。在创建SomethingController 的每个实例之前,我需要注册HttpRequestMessage,以便它可以在LinkGenerator 层使用。

标签: castle-windsor


【解决方案1】:

Mark Seemann 的 this 库是答案吗?在描述中他明确写道:

这种方法可以使用依赖注入 (DI),因为 request 可以被注入到需要它的服务中。

然后举个例子:

// 在 ApiController 内部

var uri = this.Url.GetLink(a=> a.GetById(1337));

然后您可以通过它在您注入控制器的服务中传递 URL。

更新: Mark Seemann 写了同样的问题here

“因为 HttpRequestMessage 提供了您可能需要的上下文 组成依赖图,最好的扩展点是 每次提供一个 HttpRequestMessage 的扩展点 图应该组成。这个扩展点是 IHttpControllerActivator 接口:..."

通过这种方式,您可以通过从 HttpRequestMessage 获取并将其传递给 DI 容器,将请求上下文信息传递到对象图中深处的组件。 看看IHttpControllerActivator的界面就知道了。

WEB API框架通过DependencyResolver获取IHttpControllerActivator。您可能已经用您的 CastleWindsorDependencyResolver 替换了它。现在您必须实现并注册您的 HttpControllerActivator 并注册它。

当 WEB API 框架从 DependencyResolver(您的 Castle Windsor DR)获取 IHttpControllerActivator 并调用 IHttpControllerActivator.Create() 时,它会将 HttpRequestMessage 传递给您。您可以在调用 Resolve(typeof(MyController)) 之前从那里获取您的信息并将其传递给您的 CastleDR,这将解析整个对象图 - 这意味着您将有 MyHttpContextInfo 注入解析堆栈深处的 XYZComponent。

这种方式是在最后可能的时刻传递参数,但它仍然是可能的。在温莎城堡中,我通过 CreationContext.AdditionalArguments["myArgument"];.

【讨论】:

  • 如果它有一个特定于温莎城堡的具体答案。不过,感谢您指出图书馆。
  • 但是有一个确切的例子:>// 在 ApiController 内部 >var uri = this.Url.GetLink(a => a.GetById(1337));
  • 我的问题需要下游注入拒绝信息。控制器不使用请求,它使用使用请求的组件。
  • @RichardSzalay 看看我的答案的更新。我想这是正确的答案。
【解决方案2】:

鉴于缺乏一种干净的方式来执行此操作,并且 Web API 没有提供关于每个请求上下文对象之外的托管端点的信息,我最终从配置中注入了基本 url。

【讨论】:

    【解决方案3】:

    我需要在创建每个之前注册 HttpRequestMessage SomethingController 的实例,以便它可以在以下位置使用 LinkGenerator 层。

    听起来您想在运行时(启动后)向容器注册一个项目。一般来说,这不是一个好的做法——注册应该是在应用启动时发生的离散事件,并且容器的状态不应在运行时更改。

    依赖注入是关于解析服务组件,而不是运行时状态——状态通常通过方法(方法注入)传递。在这种情况下,听起来您的 LinkGenerator 组件需要访问请求的环境状态。

    我对 HttpRequestMessage 不是很熟悉,但this answer 似乎表明可以从 HttpContext.Current 中检索它。您可以将此作为 LinkGenerator 类上的方法,或者将此调用包装在一个单独的组件中,该组件将注入 LinkGenerator (HttpRequestMessageProvider?)。后者将是我的首选方法,因为它使 LinkGenerator 更易于测试。

    【讨论】:

    • 如果LinkGenerator 使用了方法注入,那么SomethingService 也需要方法注入,其唯一目的是提供给LinkGenerator。对我来说,这听起来像是一种泄漏的依赖。此外,该链接依赖于 WebHost / System.Web,我不想介绍它。
    • 对——通过方法注入传递状态两层深是一种明显的设计气味。第二种选择显然更好,但如果这不起作用,您可能需要认真考虑这是否是 DI 可以有效解决的问题。无论如何,我强烈建议不要使用任何涉及在运行时注册或重新注册的解决方案。
    【解决方案4】:

    正确的做法是

    1. 创建 IMyDesiredRouteParameterProvider
    2. 实施它。获取里面的当前请求并获取url
    3. 注册它并通过构造函数将其注入所需的依赖类中。

    我自己做了一个这样的实现,我可以说这种方式效果很好。您可以制作 Web.Infrastructure 程序集并将实现放在那里。如果您要从另一个 Web 模块引用它,或者将接口和实现都放在那里。

    using System;
    using System.Web;
    
    namespace RouteParameterProvider
    {
        interface IMyRouteParameterProvider
        {
            string GetRouteParameter();
        }
    
        public class ControllerActionMethodRouteParameterProvider : IMyRouteParameterProvider
        {
            public string GetRouteParameter()
            {
                string Parameter = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"] as string;
                if (string.IsNullOrEmpty(Parameter))
                {
                    throw new InvalidOperationException();
                }
                return Parameter;
            }
        }
    }
    

    您可以从以下位置获取请求上下文包含的所有可能内容:

    HttpContext.Current.Request.RequestContext

    如果你重新考虑你的设计决定会更好:

    我需要在创建每个之前注册 HttpRequestMessage SomethingController 的实例,以便它可以在以下位置使用 LinkGenerator 层。

    容器将在运行时初始化,然后用于解析。

    【讨论】:

    • HttpContext 仅在 Web 主机上可用,我无法访问。
    • 搜索并深入挖掘 WEB API 以获得这样的解决方案,并且不要注册每个 web 调用的东西 - 这是一种不好的做法。您的问题已解释并解决here 并在一些文章中指出here
    • 我已经深入挖掘并且没有成功,因此我提出了我的问题。这个问题:1)使用统一 2)在已经注册的服务上调用方法。这些都没有授予我访问权限来解析我托管的 Web api 应用程序的绑定端点。
    猜你喜欢
    • 1970-01-01
    • 2019-03-23
    • 2016-06-19
    • 1970-01-01
    • 1970-01-01
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    相关资源
    最近更新 更多