【问题标题】:Delay creation of instance in Simple Injector在 Simple Injector 中延迟创建实例
【发布时间】:2017-02-04 09:25:09
【问题描述】:

我在我的项目中使用 Simple Injector 来连接所有必需的依赖项,但我无法调用 container.Verify,因为它会在实际的第一个请求之前为 http 配置创建一个 Singleton 实例

public interface IConfiguration { }
public class Configuration : IConfiguration
{
    public Configuration()
    {
        var httpContext = HttpContext.Current;
        var httpRequest = currentHttpContext.Request;
        var httpRequestUrl = currentHttpRequest.Url;

        this.UriScheme = currentHttpRequestUrl.Scheme;
        this.UriHost = currentHttpRequestUrl.Host;
        this.UriPort = currentHttpRequestUrl.Port;
    }

    public string UriScheme { get; private set; }
    public string UriHost { get; private set; }
    public int UriPort { get; private set; }
}

public class ServiceA
{
    private readonly _configuration;

    public ServiceA(IConfiguration configuration) 
    {
        _configuration = configuration 
    }
}

public class ServiceB
{
    private readonly _configuration;

    public ServiceB(IConfiguration configuration) 
    {
        _configuration = configuration
    }
}

这是场景的一个基本示例。我目前有大约 60 个服务,全部取决于 IConfiguration

所有配置都需要在创建配置类时进行

这就是我在容器中注册实例的方法

var container = new Container();

//container.RegisterSingleton<IConfiguration, Configuration>();

var lazy = new Lazy<InstanceProducer>(() =>
    Lifestyle.Singleton.CreateProducer(typeof(IConfiguration), typeof(Configuration), container));

container.Register<ServiceA>();
container.Register<ServiceB>();

container.Verify(); // Creates configuration class --> not desired

根据How can I skip verification of an object in the container

所以这里的技巧是在验证过程之后触发创建新的InstanceProducer 实例

我知道解决方法是使用 Lazy&lt;T&gt;InstanceCreator,但我无法正确完成挂钩代码

编辑

Configuration 类没有依赖关系。 Configuration 的问题在于,它在 container.Verify 方法调用上被创建为 Singleton,而当时 currentHttpRequest.Url 不是实际的 url

我想我可以将配置从构造函数移动到方法(例如GetConfiguration)并进行一些重构,但我很好奇在问题的场景下是否可以实现延迟实例创建

【问题讨论】:

  • 请详细说明Configuration 类的哪些部分阻止它被创建以及它有哪些依赖项。最好显示一些真实的代码。
  • 此外,您阅读了this article,其中指出应用程序组件(例如Configuration)的构建不应依赖于任何可能失败的事物,就像您的情况一样?
  • @Steven:查看已编辑的问题

标签: c# .net dependency-injection inversion-of-control simple-injector


【解决方案1】:

正如 Mark Seemann 在this 文章中所解释的,注入构造函数应该简单可靠。他们不应该做任何可能导致它失败的事情。在构造函数中调用 HttpContext.Current 会使其不可靠,因为这可能会失败。

除此之外,您的 Configuration 组件现在依赖于运行时数据(HttpContext.Current 运行时数据),这是一种罪过,如 this article 中所述。

但是,您的问题的解决方案非常简单明了。只需将您的 Configuration 类更改为以下内容:

public sealed class Configuration : IConfiguration
{
    public string UriScheme => this.Url.Scheme;
    public string UriHost => this.Url.Host;
    public int UriPort => this.Url.Port;
    private Uri Url => HttpContext.Current.Request.Url;
}

这不仅简化了事情,还消除了您正在应用的反模式,这些反模式会给您带来麻烦。您的构造函数现在非常简单,甚至不再存在(不能比这更简单了)。现在仅在构造对象图后才请求运行时数据(来自HttpContext.Current)。这允许容器可靠地验证其配置。

【讨论】:

  • 感谢您的回复史蒂文。我完全同意我不应该在构造函数中包含运行时数据...您的答案确实解决了container.Verify 问题,但我仍然对LazyInstanceCreator 的动态以及如何应用它们来绕过container.Verify
  • 根据Issue 227,这是一件微不足道的事情,但我无法弄清楚
  • @TMiNus 这是一个显然只会使您的情况复杂化的结构。事实上,您的问题链接到的答案描述了一个非常特殊的异常,它仅由不可更改的遗留代码证明。这种结构应该仅在真正例外的情况下使用。
  • 我的观点是,如果我将来遇到特殊情况,我将无法应用该构造,我真的很喜欢 Simple Injector,所以我将开始在我所有的项目中使用它,因此我认为这是一个在我面临类似情况之前的时间问题
  • @TMiNus 如果您遇到这种真正特殊的情况,请在此处或 Github 上发布一个包含所有详细信息的新问题。每个案例都需要自己的分析,都应该得到分析和具体答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-18
  • 2014-11-23
相关资源
最近更新 更多