0

I have recently started a small project (C# .Net console application) and I'm trying to use dependency injection "properly" with Castle Windsor as my DI container.

I am not entirely new to dependency injection since I've been unit testing for some time. I feel I've been doing OK so far but have run into a scenario where I feel I must instantiate an object far from the composition root.

In my data access layer I am using the Entity Framework (6) to get data from my database. This is all hidden behind interfaces that are defined in my domain logic layer.

I need to add a new log record, here is an abridged and edited version of my code;

public class Logger:ILogger
{
    private readonly IContext _context;
    public Logger(IContext context)
    {
        _context = context;
    }

    public void Write(string message)
    {
        var log = new Log();
        log.Message = message;
        context.Logs.Add(Log);
        context.Save();
    }
}

Log implements the ILog interface;

public interface ILog
{
    string Message { get; set; }
}

This is a solution I have used in the past because it is possible to unit test this code but I am no longer injecting all my dependencies.

I have considered method injection (i.e pass an ILog in with the message), but where would the class that is consuming this code get it's instance from? The same problem is true if I were to inject a factory, it takes the problem out of this class and moves it to another.

I suspect that the solution (if one is required) lies in how I set up the object lifetime of the instances of ILog.

In my real implementation I have a Controller class that takes an instance of ILogger. I can register concrete implementations for Controller, ILogger and IContext with my DI container and I can resolve an instance of Controller and run the application but at run-time I need an unknown number of Log instances.

How can I push the creation of Log instances back to my DI container? Is this something I should be trying to do?

mark_h
  • 5,233
  • 4
  • 36
  • 52
  • 2
    Why does `Log` need an interface `ILog`? Isn't `Log` a simple DTO? Can you think of a scenario where you would need a different implementation of `ILog`? – Yacoub Massad Sep 14 '16 at 09:50
  • Why would you create multiple instances of Log?shouldnt you be using singleton? – Rohit Sep 14 '16 at 09:54
  • Yacoub Massad - I knew someone would point that out. The answer is maybe?, our database is undergoing some heavy changes. The Log implementation I have knows how to map itself to several different tables, but these tables are likely to change. – mark_h Sep 14 '16 at 09:56
  • Rohit - I believe I need to create multiple instances because if I passed one in, when I saved it would simply keep updating the same log record in the database rather than creating new records each time the write method is called – mark_h Sep 14 '16 at 09:58
  • @mark_h, can you show the current `Log` implementation and shed more light on how it maps itself to different tables? – Yacoub Massad Sep 14 '16 at 11:43
  • @YacoubMassad - Not in a simple, concise manner and I don't see how this would relate to the question I asked. I need to add new records to my DB via Entity Framework. The only way I know how to do this is to create a new instance new object and add it to the DBSet of my entity context, I therefore cannot use dependency injection. My example is specific, but in a more general sense if I have an object with a singleton lifetime surely all of it's dependencies would would be single instances, even if I set their lifetimes to "per request" in my DI container – mark_h Sep 14 '16 at 11:51

1 Answers1

-1

In general - you shouldn't need a DI here. DI does not mean you can't use 'new' operator at all. Yes you can and domain classes are very good example where you would use it.

But if there is some complex scenario that you want to abstract creation on Log instances, you can always use factory pattern:

public interface ILogFactory
{
    ILog Create();
}

public class DefaultLogFactory : ILogFactory
{
    public ILog Create()
    {
        return new Log();
    }
}

This factory is now injectable and exchangeable. But like I said, you probably don't need or want that.

Łukasz Rozmej
  • 249
  • 2
  • 8
  • In my question I did state that I had considered the factory pattern but had avoided it because it simply moves the problem. Now your factory is creating new instances rather than the original class. What would be the point? – mark_h Sep 14 '16 at 11:41
  • You can exchange factories easily in config. But like I said - you probably don't need any abstraction at all here! – Łukasz Rozmej Sep 14 '16 at 12:44