How can I handle exception raised during Castle Windsor optional property injection?

1k views Asked by At

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?

2

There are 2 answers

0
Leniel Maccaferri On BEST ANSWER

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

0
Aleš Roubíček On

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.)