【问题标题】:Exception thrown Constructor Injection - AutoFac Dependency Injection异常抛出构造函数注入 - AutoFac 依赖注入
【发布时间】:2015-07-13 23:42:42
【问题描述】:

我有一个 Autofac DI 容器并使用构造函数注入将配置设置注入我的 SampleClass。 Configuration Manager 类创建为 singleInstance,因此使用相同的单个实例。

public ConfigurationManager()
{
    // Load the configuration settings
    GetConfigurationSettings();
}

public SampleClass(IConfigurationManager configurationManager)
{
    _configurationManager = configurationManager;
}

我正在从配置管理器的构造函数中的 App.config 文件加载配置设置。我的问题是我也在验证配置设置,如果它们不在 App.config 文件中,则会引发异常,从而导致程序崩溃。这意味着我无法处理异常并返回响应。

我做错了吗?有没有更好的方法来加载配置设置或者有没有办法处理抛出的异常。

编辑

ConfigurationManager configurationManager = new ConfigurationManager();
configurationManager.GetConfigurationSettings();
//Try catch around for the exception thrown if config settings fail

//Register the instance above with autofac
builder.Register(configurationManager()).As<IConfigurationManager>().SingleInstance();


//Old way of registering the configurationManager
builder.Register(c => new ConfigurationManager()).As<IConfigurationManager>().SingleInstance();

【问题讨论】:

  • 细节太少了。解决方案取决于你初始化容器的方式,解析SampleClass,使用它等等。如果你处理异步、同步或多线程,很难给出一个通用的建议。

标签: dependency-injection autofac


【解决方案1】:

你做的绝对是正确的。为什么?当应用程序配置不正确时,您正在阻止系统启动。您最不想发生的事情是系统实际启动并稍后失败。快速失败!但是,请确保此异常不会丢失。您可以确保记录异常。

一个注释。一般的建议是在类型的构造函数中尽可能少做。只需将传入的依赖项存储在实例变量中即可。这种类型的构造非常快,并且永远不会真正失败。一般来说,建立依赖图应该很快并且不应该失败。在您的情况下,这实际上不是问题,因为您希望系统尽快失败(在启动期间)。尽管如此,为了遵守一般建议,您可能希望在该类型之外提取此验证过程。因此,不要在该构造函数中调用GetConfigurationSettings,而是直接从组合根(连接容器的代码)调用它,并将有效的配置设置对象提供给ConfigurationManager 的构造函数。这样,您不仅可以使ConfigurationManager 更简单,而且可以让系统更快地失败。

【讨论】:

  • 感谢您的回复。我不确定您的意思是“向 ConfigurationManager 的构造函数提供有效的配置设置对象” ConfigurationManger 只是一个保存和验证配置设置的对象。您的意思是在我设置 DI 容器之前创建一个 configurationManager 实例.验证参数,如果它们有效,则将该实例提供给 DI 容器。查看更新的主要答案
【解决方案2】:

核心问题是您通过在组合期间执行一些执行来混合对象图的组合和执行。在 DI 风格中,构造函数应该尽可能简单。当您的班级被要求执行一些有意义的工作时,例如调用 GetConfigurationSettings 方法时,这是您认真开始的信号。

以这种方式构建事物的主要好处是它使一切变得更加可预测。合成过程中的错误确实合成错误,而执行过程中的错误确实执行错误。

工作时间也更容易预测。我意识到应用程序配置在运行时并没有真正改变,但是假设你有一个读取文件的类。如果您在合成期间在构造函数中读取它,则文件的内容可能会在您在执行期间使用该数据时发生变化。但是,如果您在执行期间读取文件,则可以保证避免这种缓存形式不可避免地出现的时间问题。

如果缓存是您算法的一部分,就像我想象的 GetConfigurationSettings 一样,那么将其作为执行而不是组合的一部分来实现仍然是有意义的。缓存值的生命周期可能与 ConfigurationManager 实例不同。即使他们这样做了,将其编码到构造函数中也只有一种选择,因为执行时缓存提供了更大的灵活性并且它解决了您的异常模糊问题。

【讨论】:

    【解决方案3】:

    我不会将在合成时抛出异常称为一种好习惯。之所以如此,是因为组合可能具有相当复杂和间接的执行逻辑,使得合理的异常处理几乎不可能。我怀疑你能发明什么比糟糕的更好的东西

    try
    {
      var someComponent = context.Resolve<SampleClass>();
    }
    catch
    {
      // Yeah, just stub all exceptions cause you have no idea of what to expect
    }
    

    我建议重新设计您的类,使其构造函数不会抛出异常,除非它们确实确实需要这样做(例如,如果它们对于空值构造函数参数绝对无用)。然后,您将需要一些方法来初始化您的应用、处理错误并可能与用户进行交互。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 2019-04-20
      • 1970-01-01
      • 1970-01-01
      • 2013-01-30
      • 2012-02-12
      相关资源
      最近更新 更多