0

Castle Windsor 3.2 provides a cool addition that is Diagnostic logging in the container. This helped me redirect the container logs to a log4net log file that's being used to store the application logs.

What I'd like to do now is to be able to actually catch the Exception the container detects while injecting my optional property.

In my specific situation, an Oracle database error ORA-28000: the account is locked was being raised while Castle tried to execute my code to inject the Database property in a BaseController class:

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; }
}

This Database property is null when I'm inside an action method in an Controller that inherits from BaseController. This all happens because Castle Windsor "swallows" the exception. The only message the user gets is: Object reference not set to an instance of an object. OK but I'd like to show the real exception/reason to the user, that is, ORA-28000: the account is locked. This message gets logged by Castle Windsor thanks to the aforementioned Diagnostic logging. This is cool but I want to be able to really catch the exception inside the catch block:

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);
        }
    }

}

Is this scenario possible with property injection?

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
  • what's your code doing to cause the exception to be thrown? This sort of code (trying to access the database) is best not executed as part of external object initialisation (like when setting a property) but if you want to act on it, and compensate for errors, it should become part of your core domain I'd suggest – Krzysztof Kozmic Jan 09 '14 at 22:03
  • @KrzysztofKozmic Yep... during the `Database` property initialization/injection, there's a check to make sure that the `connection string` passed through Castle's `DependsOn` from `Web.config` is right and we try to open a database connection just to test if it's right. Then we close that connection immediately and the initialization is done. That's the problem: the user passed in the connection string was locked (ORA ex shown above) and that ex was being `swallowed` by Windsor. Now at least with the help of built in Logging diagnostics I can catch that exception in a log4net log file. – Leniel Maccaferri Jan 09 '14 at 22:20

2 Answers2

1

As Krzysztof Kozmic mentioned in his comment we should not have any code that tries to do external object initialization while injecting a property.

My problem as I describe in this subsequent comment was that I was trying to open a database connection while initializing the property.

I removed that code and now the exception is only raised in my own domain code when that injected property is used for the 1st time.


Today I hit this same problem: one thing that helped me figure out the error was to momentarily use Constructor injection instead, like this:

private OEVizion _database;

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

Doing this I was able to see what was the error: version mismatch between log4net - the one in the OEVizion class library and the one used in the .Web project.

After getting the EF context correctly initialized I got back to Property injection and I'm back in business. :D

Community
  • 1
  • 1
Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
0

When you have optional dependencies it is always better to use the Null Object pattern.

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

It prevent the NullReferenceException and you can provide behavior you expect (do nothing, throw specific exception, log to trace etc.)

Aleš Roubíček
  • 5,198
  • 27
  • 29