Search code examples
c#dependency-injectioninversion-of-control

C# IoC Instantiation when the injected objects are conditional


I have an IoC question that for the moment is abstract. I have not yet chosen an IoC framework for started coding. I am still mentally planning the methods I am going to use for an imminent project.

My coding style generally follows this pattern:

  • A Processor of some kind is instantiated and passed a Business Object.
  • The processor in turn will instantiate a Validator to validate that the passed business object is valid for the given process.
  • If the Business Object is found to be valid, then a Persistence Object will be instantiated. The Persistence object is responsible for transformations such as encryption, caching, and grouping multiple requests together in a single transaction for object graphs.
  • Then, the business object instantiates a DataLayer that will have the job of persisting the Business Object to the database, or pulling it from the database as the case may be (or a text file, or a webservice, whereever the data may live.)
  • My ideal structure is that a Processor knows about a Validator and a Peristence object, but not an AccessLayer. A persistence object knows about an access layer, but cannot directly instantiate or invoke a process. This way there are clearly defined layers that can be seperated as necessary
  • Finally, this process is agnostic to input or output and immutable based on the application type. In other words, I could use the same Processor to add a business object in a web app as I would in a desktop app. Obviously, the Model/View/Controller would change depending on the app type, but the rules for adding or selecting a business object remain universal.

My problem is this. I don't like that my AccessLayer in turn needs to pull the connection string from the config file, for instance. Maybe I want my users to be able to specify a config file or a Db Table for settings. Having the access layer check the config file to see if it should use the config file is circular and silly. And the Access Layer cannot likewise call a Persistence object to pull the settings, or query the Application Framework to see if it is a web app with a Web.Config or a desktop app with DbSettings.

So I was thinking that the best thing for me to do is to use an IoC container of some kind. I could then inject whatever settings I needed. This could also allow me to mock objects for testing, which is another difficult (but not impossible) task with my current method. So from my reading, my vague Processor implementation would look like this:

public class VagueProcessor{
   public VagueProcessor(IValidator validator, 
                         IPersistence persistence, 
                         IAccessLayer accessLayer,
                         ISettings settings) { ... }
}

Here is my snag. In the application I am planning, the Business Object have a variety of implementations each with their own configurable rules. Say one BO is for the state of CA and another for the state of NY, and both states have their own special rules to be validated by their governing bodies. So the validator could be a CAValidator or a NYValidator just depending on the state of the Business Object.

Ok, so my question after all that preamble and backstory is this: in this scenario, would I pass a ValidatorFactory to the Processor and the Factory would instantiate the appropriate type of Validator based on the state of the Business Object? And if so, would I register each type with the IoC container, or just the Factory?

Thanks for your thoughts on this matter!!


Solution

  • That's a vague question as you don't have a problem yet, only the idea.

    From what I understand from your question, I'd say:

    1. The IOC solves the problem of creating the new object, not exactly deciding which object to create. In most IOC containers you can at some level choose the implementation you're asking, but in your case the logic looks very application centric, and no IOC container will help you deciding which one to use. In that case, you should indeed have a factory passed to your processor where you can ask something like factory.CreateValidatorFrom(myBusinessObject).

    2. Internally, that factory can still use DI to instantiate each component. If you use .NET Core DI for example, you can pass a IServiceProvider to the factory, and call inside the factory serviceProvider.GetService<CAValidator>(). All DI providers will have an object like that.

    So, in a sense, the factory and the DI can co-exist and each of them solve part of the problem. If you're using DI, you shouldn't ever have to instantiate the actual class. That will make it easier for each validator to have their own dependencies and you don't have to care how to get them.

    And yes, in that case you'd register each validator in the DI, and also the factory. In cases like this, you can easily loop through all of them through reflection and register them dynamically by name or interface, if that is bothering you.

    And in the end, if you're using .NET Core, I strongly suggest you to simply use the built-in DI. It's simple and good enough for most cases.