【问题标题】:How can I handle exception raised during Castle Windsor optional property injection?如何处理 Castle Windsor 可选属性注入期间引发的异常?
【发布时间】:2014-01-08 22:35:48
【问题描述】:

Castle Windsor 3.2 提供了一个很酷的附加功能,即Diagnostic logging in the container。这帮助我将容器日志重定向到用于存储应用程序日志的 log4net 日志文件。

我现在想做的是能够在注入我的可选属性时实际捕获容器检测到的Exception

在我的具体情况下,当 Castle 尝试执行我的代码以在 BaseController 类中注入 Database 属性时,引发了 Oracle 数据库错误 ORA-28000: the account is locked

public class BaseController : Controller
{
    /// <summary>
    /// Repository interface injected by Castle Windsor IoC container.
    /// See <see cref="MyProject.Widgets.CastleWindsor.Facilities.PersistenceFacility.Init()"/> for more information.
    /// </summary>
    public ILogRepository Database { get; set; }
}

这个Database 属性是null,当我在一个继承自BaseController 的控制器中的操作方法中时。这一切都是因为温莎城堡“吞下了”例外。用户收到的唯一消息是:Object reference not set to an instance of an object。好的,但我想向用户展示真正的异常/原因,即ORA-28000: the account is locked。由于前面提到的诊断日志记录,这条消息被 Castle Windsor 记录下来。这很酷,但我希望能够真正捕捉到 catch 块内的异常:

public class SubCatListController : BaseController
{
    public ActionResult SubCatList(string subcat)
    {
        try
        {
            var sub = Database.GetLogSubCategory(subcat);
        }
        catch(Exception e) // I'd like to get the real exception from Castle Windsor here...
        {
            Logger.Error(e.Message, e);
        }
    }

}

这种情况可以通过属性注入实现吗?

【问题讨论】:

  • 你的代码做了什么导致异常被抛出?这种代码(试图访问数据库)最好不要作为外部对象初始化的一部分执行(比如设置属性时),但是如果你想对它采取行动并补偿错误,它应该成为你核心域的一部分我建议
  • @KrzysztofKozmic 是的...在Database 属性初始化/注入期间,检查以确保connection stringWeb.config 通过Castle 的DependsOn 是正确的,我们尝试打开数据库连接只是为了测试它是否正确。然后我们立即关闭该连接并完成初始化。这就是问题所在:传入连接字符串的用户被锁定(如上所示的 ORA 前),并且该前是 Windsor 的swallowed。现在至少在内置日志诊断的帮助下,我可以在 log4net 日志文件中捕获该异常。

标签: exception exception-handling dependency-injection castle-windsor property-injection


【解决方案1】:

正如 Krzysztof Kozmic 在他的 comment 中提到的那样,我们不应该有任何代码在注入属性时尝试进行外部对象初始化。

我在后续comment 中描述的问题是我在初始化属性时试图打开数据库连接。

我删除了该代码,现在只有在我自己的域代码中第一次使用注入的属性时才会引发异常。


今天我遇到了同样的问题:帮助我找出错误的一件事是暂时使用Constructor injection,如下所示:

private OEVizion _database;

public ReportingPeriodsController(OEVizion database)
{
    _database = database;
}

这样做我可以看到错误是什么:log4net 之间的版本不匹配 - OEVizion 类库中的一个和 .Web 项目中使用的那个。

在正确初始化 EF 上下文后,我回到了Property injection,我又重新开始工作了。 :D

【讨论】:

    【解决方案2】:

    当您有可选依赖项时,最好使用Null Object pattern

    public BaseController() {
        Database = NullLogRepository.Instance;
    }
    

    它可以防止NullReferenceException,并且您可以提供您期望的行为(什么都不做、抛出特定异常、记录到跟踪等)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 2014-06-10
      相关资源
      最近更新 更多