This project is read-only.

bootstrap code, container locking (again) and EasyNetQ

May 13, 2014 at 5:33 PM
Edited May 14, 2014 at 11:29 AM
Hi. Coming from Funq and Structure Map I am a happy Simple Injector user for about a year now, and I try to inject SI in most-if-not-all of my .NET projects.

With regards to bootstrap code and with regards to using SI as a container for EasyNetQ, I have a two part question, but both parts are related.

1) When registering services in a bootstrap class, I sometimes need to create classes on-the-fly before registering those in the container, because subsequent classes depend on this classes. I cannot resolve this classes via the container, because this would lock the container, even though the registration process is not finished. A good example is configuration, I have a class that provides persistent configuration, using either Ini, XML or Registry. All settings (POCOs) need this dependency to load/save themselves. So I end up with code like
appInfo = new AppInfo(); // where files are located
appConfig = new AppConfigIni(appInfo); // use Ini-file

// a bunch of settings, depend on AppInfo&AppConfig
logSettings = new LoggingSettings(appInfo, appConfig);
svcSettings = new ServiceSettings(appConfig);
dbSettings = new DatabaseSettings(appConfig);
queueSettings = new QueueServerSettings(appConfig);
scheduleSettings = new SchedulerSettings(appConfig);

// register those settings
container.RegisterSingle<AppInfo>(appInfo);
container.RegisterSingle<AppConfig>(appConfig);
container.RegisterSingle<LoggingSettings>(loggingSettings);
// etc.

// now load the settings from the configuration file
appConfig.Load();

// now logging is working as configured and we can
// register db-connections, queues, scheduler
// as the configuration information for db-username/password/database
// queue-host/port, scheduler interval or cron schedule etc. is loaded
The above code works, but seems not elegant. However the issue is that types/interfaces - with external persistence - registered in the container, needed by subsequent types also being registered in the container, cannot be resolved and loaded during registration.

2) A comparable issue came up with the RabbitMQ wrapper EasyNetQ, see issue No. 198 after the registration process has been re-factored, see there for details.

I am a strong advocate for SIs container lock policy, not only because it is a deleberate design strategy, but also it leads to cleaner code. Notwithstanding I have no good solution within the spirit of SI to resolve the above issues.

Ideas anyone?
May 13, 2014 at 6:03 PM
Edited May 13, 2014 at 8:37 PM
Hi Skipper,

About your first question:

I'm not sure I really understand your specific design issue. Might it be that your code example doesn't really show the problem, because I would say you could rearrange the registrations as follows and this won't cause the container to be locked while loading the configuration:
appInfo = new AppInfo(); // where files are located
appConfig = new AppConfigIni(appInfo); // use Ini-file

// now load the settings from the configuration file
appConfig.Load();

// a bunch of settings, depend on AppInfo&AppConfig
container.RegisterSingle<LoggingSettings>();
container.RegisterSingle<ServiceSettings>();
container.RegisterSingle<DatabaseSettings>();
container.RegisterSingle<QueueServerSettings>();
container.RegisterSingle<SchedulerSettings>();

// register those settings
container.RegisterSingle<AppInfo>(appInfo);
container.RegisterSingle<AppConfig>(appConfig);
But do take a close look at all your *Settings classes. Their registrations might be redundant. Instead of wrapping the configuration values in these *Settings classes, consider directly injecting them in the classes that need, but remember this simple rule:
If you need to inject one configuration setting in more than one service, you are probably missing an abstraction.
For instance, your DatabaseSettings class might contain an ConnectionString property and you might have many IRepository implementations that make use of this value. But if they do, you are missing an abstraction. In this case probably an IConnectionFactory of some sort. The IConnectionFactory implementation can create new connections and nobody needs to know the details of how to do that; nobody needs to know there's a connection string involved. Registering the the connection factory would be trivial:
container.RegisterSingle<IConnectionFactory>(
    new SqlConnectionFactory(dbSettings.ConnectionString));
See how the DatabaseSettings class is still used to create the SqlConnectionFactory; there's nothing wrong with that. But those *Settings classes don't need to be registered. They will most likely violate the Interface Segregation Principle, you need to change them any time the configuration changes, and they make your code harder to test.
May 14, 2014 at 10:55 AM
Edited May 14, 2014 at 11:43 AM
My bad. The snippet is missing some important information. I try to explain it in more detail, but in the end the question boils down to: How to handle types that are dependent on persistent data, that needs to be resolved during the registration process. And how to handle those types, if the persistent data (e.g. the settings) change at runtime. Think of services that are set-up/configured by a user via some GUI, and need to be registered/resolved at runtime, while other services are already registered and in use (resolved) to power this set-up/configuration process.

In the above code my setting classes are (at least can be) POCOs (object settings, comparable to ORM POCOs for database objects). Inheriting from AppSettings is just for convenience, so that all default values are set and properties are set on load, but POCOs work fine as well, if proper methods are called.
[Section("Database")]
public class DatabaseSettings : AppSettings
{
   public DatabaseSettings(AppConfig appConfig) : base(appConfig) { }

    public override void appConfig_Loaded(Object sender, AppConfigEventArgs e)
    {
        base.appConfig_Loaded(sender, e);

        this.Server = ServerFactory.CreateServer(this);
        ConnectionFactory = this.Server.GetConnectionFactory();
    }

    [defaultvalue(databaseservertype.sqlitev3)]
    public databaseservertype servertype { get; set; }

    public string database { get; set; }

    public string username { get; set; }

    [defaultvalue(false)]
    public bool trustedconnection { get; set; }

    [...]
}
With your above re-arrange, no setting has a value from the Ini-file, as the properties will not be set. The reason for this is that the settings needs to know about the appConfig before load.
public abstract class AppSettings : SettingsBase // SettingsBase sets default values
{
    protected AppSettings(AppConfig appConfig)
    {
        appConfig.Loaded += new EventHandler<AppConfigEventArgs>(this.appConfig_Loaded);
        appConfig.Saving += new EventHandler<AppConfigEventArgs>(this.appConfig_Saving);
    }
    public virtual void appConfig_Loaded(object sender, AppConfigEventArgs e)
    {
        if (e.HasLoaded)
        {
            SettingsSerializer.ReadFromConfig(this, e.ConfigSource);
        }
    }
    public virtual void appConfig_Saving(object sender, AppConfigEventArgs e)
    {
        SettingsSerializer.WriteToConfig(this, e.ConfigSource);
    }
}
The reason for having all settings in the container is, that I like to write all setting values to some log file (for reference purposes). If I create and load the settings upfront (and dump them to the log right away), I could skip adding the settings to the container. However if I have a class with a dependency to all those settings (or a collection of those settings) that dumps the settings to the log, I need to resolve the settings from the container (at least the collection). Dumping all settings is very common in finding bugs at the customers environment.

Each of my services have a dependency to one setting class, - let alone the settings dumper - (main service -> service settings, connection -> database settings, message queue -> queue settings, scheduler -> scheduler settings), and some of them need those values in the constructor. Like when creating the message bus, I need the host, port, user-name and password, when connecting to the database, I need the server, database, user-name and password.
Also my design currently lacks a good strategy when those settings are changed by the user via a GUI. My only option for now is to restart the complete service, so all settings and services are reloaded.

I have to think about the last part of your answer. Registering factories for all services instead of the service itself might solve both issues. As you said there is nothing wrong with using the setting while registering the factory. And when settings change, no restart/re-register is needed, just a new create-call to the corresponding factories. On the other hand, it looks like cheating the container, as we only register factories instead of the services, that the code really depends on. So the real dependencies are hidden behind the factories.
Thanks for your help.
Best regards

christoph
May 16, 2014 at 8:42 AM
Edited May 27, 2014 at 12:07 PM
Hi Christoph,

The ability to change configuration at runtime is a very interesting requirement, but if a simple application restart would do the trick, I would certainly go with that solution. Being able to change configuration values at runtime adds complexity to your application; there's nothing much you can do about it. It adds complexity with or without dependency injection. It adds complexity, because the volatile configuration settings need some special (mental) flag, because services should not hold on to those values, but should require them. Further more, the object created with those values (such as your IBus) should not live for the duration of the AppDomain and you need a certain release policy. DI containers might even help with that, but as you can see, it does increase the mental load on the application (developer).

But if you really need volatile configuration values, I think the best solution is indeed to have *Settings abstractions for that. But do make a clear distinction between all static configuration values and those volatile configuration values. Static values should be loaded during bootstrapping, just before you wire up your object graphs (=configure the container) and inject them directly into the classes that need them; don't use *Settings abstractions for static configuration values.

There are probably a few different directions to go with, but one approach is to request the volatile value from the *Settings from within the constructor of a service, even though in general constructors should be simple. The advantage of this for instance is that you can register those *Settings classes with a certain scoped lifestyle. By doing this, you allow a few interesting things:
  • You could simulate transaction-like behavior, where the whole object graph gets the same set of values, even if the user changes it while you are running operations in the background.
  • It allows the Diagnostic Services to verify whether all consumers of those *Settings have a lifestyle that is equal or shorter than that scoped lifestyle. This prevents having any class that accidentally lives longer (say as singleton for instance) and holds on to the old configuration value.
To be able to do this, there must be some sort of request-based design in your application. My applications (even client applications) use a request based model, but that is something that needs to be in the design. It might be hard to pull this off otherwise. And of course, you must ensure that incorrect volatile configuration values should cause the object graph from failing to resolve. Take for instance the IBus instance. It seems that when creating the bus, EasyNetQ directly connects to the bus. This is a time consuming and fragile operation and should not be done while composing the object graph. The creation of the bus instance should be delayed. You could use Lazy<T> for that. The fact that you can't connect to the bus, has nothing to do with the validity of the object graph. Delaying the creation will allow you to check the correctness of your DI configuration inside an integration test by using the Verify method and the Diagnostic API.
May 27, 2014 at 11:49 AM
Steven,

for server applications and services, an application restart (or AppDomain unload and container rebuild) is mostly an option. For client applications, an application restart because of an option change would be very unusual. I agree it adds complexity to the application, but I think changing configurations at run-time is a very common requirement, especially for client applications.
Think of your text editor, word processor or spreadsheet, image tool - you name it - wanting to restart because of a font change, auto correction change or any option change; think of Visual Studio wanting to restart because you activated line numbers, dark theme or added a keyboard shortcut. Users would consider this as awkward or clumsy software; but maybe these client applications are not best suited for DI containers.

I have looked into the scoped lifestyles and I think this gives a lot of food for thought. I also thought more about registering factories for services instead of services themselves. It implies that the services itself should not register anything, but might depend on *Settings that get resolved from the container, when a Factory.Create... is called. (This pattern e.g. would not work with EasyNetQ currently, as some "BusFactory" needs to call CreateBus that is doing registers with an already locked container.)
Using factories is some kind of delayed resolve of the service, but I am torn if it is cheating the container (hiding the service dependency) or not. Your opinion?

Also it might be worth to contemplate about whether a *Settings class is singleton or immutable (or both or neither of them). Runtime changing configurations means that a *Setting might have changing values during its lifetime (mutable), or is (re-)created when values change (= whenever it is requested to hold the current values, transient). A singleton *Setting that is mutable needs to be used carefully in multi-threaded environments. Immutable singleton *Settings imply a restart of the application in case of setting changes. A transient immutable should be loaded on creating, so it holds the current values of the configuration. (However my current setting implementation would not work like this, as it notifies all existing settings on configuration reload to update themselves; I would need to change the implementation to make it immutable). A transient mutable is what you get using my settings with a transient lifetime scope; it also needs to be used carefully in multi-threaded environments.

I definitely have to think about this more, but of course your input is highly appreciated.
May 27, 2014 at 7:47 PM
>> but maybe these client applications are not best suited for DI containers.

Dependency Injection is suited for almost all types of application, since it's just a basic pattern. Using a DI container is always optional, but DI containers are not less suited for client applications. My previous project contained a Win Forms client application and the whole thing was bootstrapped with Simple Injector. We used Simple Injector to auto-wire our Form classes that used constructor injection.

>> is cheating the container (hiding the service dependency) or not. Your opinion?

Using the factory pattern is certainly not cheating. The factory pattern is a valuable pattern. In some cases you need to postpone the building of (part of) the object graph and the way to do that is through factories.

If you apply Dependency Injection correctly however, you will often see a decrease of the amount of factories your application needs. There are many other valuable patterns that allow you postponing building of the graph, such as the Proxy Pattern. Take a look at this stackoverflow question for instance (with my answer).

>> Also it might be worth to contemplate about whether a XSettings class is singleton or immutable

If you're not worried about the user changing configuration while some running operation might be affected by that that change, the following might be more than you need, but what you can do is the following:
// using SimpleInjector.Extensions.LifetimeScoping

// Immutable class PrinterSettings
private static PrinterSettings settings = null;

private static void Bootstrap()
{
    // Initial configuration (perhaps loaded from registry or file)
    settings = new PrinterSettings("\\printer1", new DefaultOptions());

    // Register in scoped lifestyle
    container.RegisterLifetimeScope<PrinterSettings>(() => settings);
}

// Silly example. In reality you should never have calls to the container
// littered throughout your code base.
private void SomeApplicationMethod()
{
    using (container.BeginLifetimeScope())
    {
        var instance = contrainer.GetInstance<ISomeObjectGraph>();
        instance.DoSomethingUsefull();
    }
}

private void PrinterSettingsSaveButton_OnClick(object s, EventArgs e)
{
    settings = new PrinterSettings(this.PrinterNameTextBox.Value, options);
}

In this case you create an initial immutable PrinterSettings instance and store it in a private field. You register a delegate that accesses that field and returns its current instance. This delegate is registered with the Lifetime Scope lifestyle. Since the PrinterSettings is immutable, the only way to chagne it is through its reference, but since you registered it with the Lifetime Scope lifestyle, you ensure that the value will not change during such scope. So even when the user triggers the OnClick method during the execution of SomethingUsefull while you are using factories to postpone creation of part of the object graph, that whole object graph is guaranteed to have the original settings.

But if thread-safety is not an issue, you don't need this reference swapping and immutability. But you still want to have *Settings interfaces that are read-only, and have a writable interface for the parts of the system that need to update it (such as the OnClick method).
Marked as answer by skipperTux on 6/4/2014 at 10:06 AM
Jun 4, 2014 at 6:17 PM
I assume I have to re-work my settings library with regards to your input, but I think it improves my library, so I consider it a good thing.

Thanks a lot for all your valuable input, it is really appreciated. And I could go on and on and on..., but I consider my initial question answered; and the EasyNetQ topic is continuing on github.

Thanks for your excellent support and the great work on Simple Injector.
Best regards

christoph
Jun 7, 2014 at 3:57 AM
I have a scenario where the web application makes uses of plugins. The plugins register for events by implementing an IEventConsumer<T> interface. I use the RegisterAll method to register all instances for a specific IEventConsumer<T>. But later, I'd like to let an administrator install/uninstall plugins and I'd like to do that without their having to restart the web app.

Is there a way to handle that scenario with SImple Injector?
Jun 7, 2014 at 8:49 AM
@dot_NET_Junkie recently put together a solution for adding plug-ins at runtime which I'm sure you can adapt to suit your needs. I urge you though to implement disable/enable options rather than runtime uninstall - I can't see any harm in requiring a restart for uninstalling a plug-in.
private sealed class PluginCollection : IEnumerable<IPlugin>
{
    private readonly Container container;
    private ReadOnlyCollection<InstanceProducer> pluginProducers =
        new ReadOnlyCollection<InstanceProducer>(new InstanceProducer[0]);
 
    public PluginCollection(Container container)
      {
        this.container = container;
      }
 
    public void AddPlugin(Type pluginType)
    {
        var producer = Lifestyle.Transient.CreateProducer(
            typeof(IPlugin), pluginType, this.container);
 
        var producers = this.pluginProducers.ToList();
        producers.Add(producer);
        this.pluginProducers = producers.AsReadOnly();
    }
 
    public IEnumerator<IPlugin> GetEnumerator()
    {
        foreach (var producer in this.pluginProducers)
        {
            yield return (IPlugin)producer.GetInstance();
        }
    }
 
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}
This collection can be registered as follows:
Container container = new Container();
 
var plugins = new PluginCollection(container);
 
container.RegisterAll<IPlugin>(plugins);
And now you can add a newly loaded plugin long after the container has locked:
plugins.AddPlugin(typeof(Plugin1));
And you can even register a decorator around your plugins; that will be applied as well:
container.RegisterDecorator(typeof(IPlugin), typeof(PluginDecorator));
Does this work for you?