【问题标题】:Autofac property injectionAutofac 属性注入
【发布时间】:2011-12-01 15:14:20
【问题描述】:

我正在更改我的 Asp.Net MVC3 项目以使用 Autofac 将服务注入到我的控制器中。到目前为止,这非常简单。我的服务都有一个 Telerik OpenAccess db 属性,我通过构造函数(在服务基类中)注入该属性。而且我的控制器都具有用于注入的服务的构造函数属性。

我有一个名为 AuditInfo 的类,它封装了控制器的可审计属性:

public class AuditInfo
{      
    public string RemoteAddress { get; set; }

    public string XForwardedFor { get; set; }

    public Guid UserId { get; set; }

    public string UserName { get; set; }
}

我的服务类中的 OpenAccess db 属性需要将此类的实例注入其中,以便在各种数据库调用中用作审计信息。

问题在于,这不是一个可以在 Application_Start 实例化的类,因为它的至少两个属性 RemoteAddress 和 XForwardedFor 在 OnActionExecuting 的最早阶段填充,即一旦存在 Request 变量。

因此,我在我的 BaseController 类的 OnActionExecuting 方法中实例化它:

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    base.OnActionExecuting(filterContext);
    db.AuditInfo = AuditInfo;                                      
}

public AuditInfo AuditInfo
{
    get
    {
        return new AuditInfo()
        {
            RemoteAddress = this.Request.ServerVariables["REMOTE_ADDR"],
            XForwardedFor = this.Request.ServerVariables["X_FORWARDED_FOR"],
            UserId = this.UserId,
            UserName = this.UserName
        };
    }
}

所以 - 我的问题/问题是:

  1. 我不喜欢在 OnActionExecuting 中直接访问 OpenAccess db 属性。
  2. 我希望基本上将此 AuditInfo 注入到任何地方的任何 AuditInfo 属性中
  3. 我认为我不能对 AuditInfo 使用构造函数注入,因为服务依赖于 db - 控制器依赖于服务 - db 依赖于 AuditInfo 但在控制器被实例化并收到其第一个请求之前,AuditInfo 不可用。 => 循环依赖...

如何设置 autofac 以将 AuditInfo 注入到任何将其作为属性的类中?或者有没有更好的方法来回避循环依赖并使用某种形式的 lambda/lazy 构造函数属性?

即使很多请求可能是同一会话的一部分并且没有不同的 IP 地址/用户信息,AuditInfo 是否会在每次请求时都可能不必要地重新初始化?

谢谢

【问题讨论】:

  • 我不同意问题/问题 3 - 正如 Steven 指出的,您可以使用 HttpContext.Current。所以AuditInfo不依赖于控制器,所以没有循环依赖,所以你可以根据需要构造函数注入AuditInfo
  • 嗯 - 我认为这是因为建议的解决方案是使用全局静态变量来引用 Request 对象,而不是在 Request 对象自然存在的控制器内部初始化 AuditInfo 对象。我认为服务器变量在发生注入的 Application_Start 中甚至还不存在,因为必须首先调用一个动作,不是吗?

标签: asp.net-mvc-3 dependency-injection inversion-of-control autofac circular-dependency


【解决方案1】:

原来是Autofac's MVC Integration can resolve an HttpRequestBase for you。所以你不需要直接引用HttpContext.Current.Request

Autofac 在幕后实现uses HttpContext.Current。这是因为 MVC 框架在您的代码(或 Autofac 的)运行之前设置了HttpContext.Current。所以没有循环依赖——HttpContext.Current.Request 上的请求“自然存在”,就像在你的控制器中一样。 (This question 有点解释如何)

因此,您可以按照 Steven 的建议使用 IAuditInfoFactory,但要求在其构造函数中使用 HttpRequestBase,而不是使用 HttpContext.Current,如果它让您对不引用静态变量感觉更好的话。

此外,没有循环依赖,您可以根据需要构造函数注入 AuditInfo

builder.Register(c => c.Resolve<IAuditInfoFactory>().CreateNew())
    .As<AuditInfo>()
    .InstancePerHttpRequest();

【讨论】:

  • Steven 在构建正确答案的基础方面做得很好,但是缺少 HttpRequestBase 注入和 default.kramer 对这一点的添加使他的答案更加完整。不确定 - 在这种情况下,我应该如何处理正确答案的公平标记 - 请随时告诉我。现在我将 default.kramer 的答案标记为正确。谢谢
【解决方案2】:

答案是:使用工厂。

IAuditInfoFactory 注入需要它的类型,并创建如下实现:

public class HttpRequestAuditInfoFactory : IAuditInfoFactory
{
    // Service for requesting information about the current user.
    private readonly ICurrentUserServices user;

    public HttpRequestAuditInfoFactory(ICurrentUserServices user)
    {
        this.user = user;
    }

    AuditInfo IAuditInfoFactory.CreateNew()
    {
        var req = HttpContext.Current.Request;

        return new AuditInfo()
        {
            RemoteAddress = req.ServerVariables["REMOTE_ADDR"],
            XForwardedFor = req.ServerVariables["X_FORWARDED_FOR"],
            UserId = this.user.UserId,
            UserName = this.user.UserName
        };
    }
}

您可以按如下方式注册该类:

builder.RegisterType<HttpRequestAuditInfoFactory>()
    .As<IAuditInfoFactory>()
    .SingleInstance();

现在你可以注入

【讨论】:

  • 感谢您的快速回复。这应该可行,但是这个解决方案不是真的依赖于引用 HttpContext.Current.Request 并在外部上下文中从中读取变量,而不是在 HttpContext.Current.Request 的自然生命周期中存储必要的变量并将这些变量注入到松耦合的外国语境?含义 - IAudiInfoFactory 实现需要引用 System.Web 并直接了解 HttpContext.Current.Request 才能使其工作...
  • 这个特定的HttpRequestAuditInfoFactory 实现确实对HttpContext 有很强的依赖性。从这个意义上说,它是平台感知的。这不是问题,但由于这个原因,它不是(或不应该是)您的应用程序的一部分,而应该是我们所说的Composition Root (CR) 的一部分。这是应用程序的启动路径。除了 CR 之外,没有其他部分应该知道这个 HttpRequestAuditInfoFactory 的存在。应用程序只知道IAuditInfoFactory
  • 因为应用程序的其余部分知道IAuditInfoFactory,但不知道HttpRequestAuditInfoFactory,它可以很容易地将您的应用程序(部分)迁移到——例如——Windows 服务。您将需要 IAuditInfoFactory 的 Windows 服务特定实现并将其连接起来,而不是 Windows 服务的 CR(main 方法)中的 HttpRequestAuditInfoFactory
猜你喜欢
  • 2017-01-26
  • 2012-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多